jq 1.5匹配一个记录,其中2个或更多键与名称和值匹配

问题描述 投票:1回答:2

不太清楚如何清楚地问这个问题,但是给出了如下的递归结构。我如何使用walk将2个或更多关键字符串与值匹配。我不知道结果在结构中的位置。它可能是顶级或10级深。

"children": {
    "ccc": [{
        "id": "ddd",
        "des": "object d",
        "parent": "ccc",
        "other": "zzz"
    },{
        "id": "zzz",
        "des": "object z",
        "parent": "ccc",
        "other" : "ddd"
  }]
}

我想找到一个记录,其中key=id=ddd && key=parent=cccI然后想要为该记录添加新的键/值。使用.key|match("")会给我一个匹配键的值,但不是键名本身。所以搜索ddd可能会匹配idother

我已经尝试了几个组合,如果在bash中做它看起来像

match_criteria

     ((.key|match("id") and (.key|test("ddd")) 
        and 
     ((.key|match("parent") and (.key|test("ccc")) 

new_key_value

+= {"newkey":"newValue"}

将匹配语句插入

walk(if type == "object"
      then
        with_entries(if ..match_criteria.. )
      then ..new_key_value.. else . end)

所以结果应该是这样的

"children": {
    "ccc": [{
        "id": "ddd",
        "des": "object d",
        "parent": "ccc",
        "other": "zzz",
        "newkey": "newValue"
    },{
        "id": "zzz",
        "des": "object z",
        "parent": "ccc",
        "other":"ddd"
  }]
}

基于@peak答案中的反馈更新我已更新代码如下

jsonOut=$(jq 'walk(when(type == "object";
              with_entries(
                  when(any(.value[]; .id == "ddd");
                           .value[] += {"newkey": "newValue"}
                            ))))' <<< ${jsonIn})

不幸的是,这仍然存在两个悬而未决的问

a)此代码将{"newkey": "newValue"}添加到搜索条件为真的所有子项,即:id:ddd && id:zzz,而不仅仅是id:ddd记录

"children": {
        "ccc": [{
            "id": "ddd",
            "des": "object d",
            "parent": "ccc",
            "other": "zzz",
            "newkey": "newValue"
        },{
            "id": "zzz",
            "des": "object z",
            "parent": "ccc",
            "other":"ddd",
           "newkey": "newValue"
      }]
    }

b)在any条款中添加多个部分标准。我尝试使用AND|加入方法,但这会引发错误。

when(any(.value[]; .id == "ddd" | .other == "zzz"); //no match, no value added
or
when((any(.value[]; .id == "ddd") AND (any(.value[]; .other == "zzz"));
     //error : unexpected ')', expecting $end
or
when(any(.value[]; .id == "ddd", .other == "zzz"); //no match, no value added

你能告诉两个问题的语法吗?

UPDATE2理解when更好地过滤了一个更小的,我现在已经嵌套了这些,它似乎可以缩小结果集。但是,当匹配为真时a)更新两个记录的问题仍然存在。

jsonOut=$(jq 'walk(when(type == "object";
          with_entries(
                       when(any(.value[]; .id == "ddd");
                        when(any(.value[]; .other == "zzz");
                            .value[] += {"newkey": "newValue"}
                            )))))' <<< ${jsonIn})

jsonIn

{"children": {
    "ccc": [{
        "id": "ddd",
        "des": "object d",
        "parent": "ccc",
        "other": "zzz"
    },{
        "id": "zzz",
        "des": "object z",
        "parent": "ccc",
        "other":"ddd"
  }],
  "www": [{
        "id": "ddd",
        "des": "object d",
        "parent": "www",
        "other": "ppp"
   },{
        "id": "kkk",
        "des": "object z",
        "parent": "www",
        "other":"ddd"
  }]
}}

jsonOut

{
    "children": {
        "ccc": [{
            "id": "ddd",
            "des": "object d",
            "parent": "ccc",
            "other": "zzz",
            "newkey": "newValue"
        }, {
            "id": "zzz",
            "des": "object z",
            "parent": "ccc",
            "other": "ddd",
            "newkey": "newValue" <=need to NOT add this entry
        }],
        "www": [{
            "id": "ddd",
            "des": "object d",
            "parent": "www",
            "other": "ppp"
        }, {
            "id": "kkk",
            "des": "object z",
            "parent": "www",
            "other": "ddd"
        }]
    }
}
json bash jq
2个回答
1
投票

以下是对“更新”问题的回复:

walk(when(type == "object";
          with_entries(when(.key|test("ccc");
                            .value |= map( when(.id=="ddd";
                                      . + {"newkey": "newValue"}))))))

p.s.

将来,请遵循mcve指南:http://stackoverflow.com/help/mcve


0
投票

在这里使用walk最简单的方法是在if ... then ... else ...end的“then”部分包含更新。为了强调和澄清这一点,并缩短解决方案,我将使用通用辅助函数when

def when(filter; action): if (filter?) // null then action else . end;

现在可以用非常简单的方式编写问题的解决方案:

walk(when(type == "object";
          with_entries(when(.key|test("ccc");
                       when(any(.value[]; .id == "ddd");
                            .value += ["ADDITIONAL"])))))

当然,您可能需要比.id ==“ddd”更高级的测试,并且您可能希望每个“ccc”对象仅执行一次更新,但是将使用相同的结构。

实际上,您可能还希望将上述表达式包装在def中,以便更容易进行参数化和维护。

© www.soinside.com 2019 - 2024. All rights reserved.