简体   繁体   English

jq 1.5 匹配 2 个或多个键匹配名称和值的记录

[英]jq 1.5 match a record where 2 or more keys match names and values

Not quite sure how to ask the question clearly but, given a recursive structure as below.不太确定如何清楚地提出问题,但是,给出如下递归结构。 How would I use walk to match 2 or more key strings to values.我将如何使用walk将 2 个或多个键字符串与值匹配。 I will not know where in the structure the result will be.我不知道结果会在结构中的哪个位置。 It could be the top level or 10 levels deep.它可能是顶级或 10 级深。

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

I would like to find a record where key=id=ddd && key=parent=ccc I would then like to add a new key/value to that record.我想找到一个记录,其中key=id=ddd && key=parent=ccc然后我想向该记录添加一个新的键/值。 Using .key|match("") will give me a match to the value of the key but not the key name itself.使用.key|match("")会给我一个匹配键的值而不是键名本身。 So searching for ddd may match both id and other .所以搜索ddd可能匹配idother

I have tried several combos and if doing in bash it would look something like我已经尝试了几种组合,如果在 bash 中进行,它看起来像

match_criteria匹配标准

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

new_key_value新键值

+= {"newkey":"newValue"}

insert match statement into将匹配语句插入

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

so the result should look like所以结果应该是这样的

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

UPDATE based on feedback in the answer from @peak i have updated the code as follows根据反馈意见,从@peak答案UPDATE我已经更新如下代码

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

unfortunately this still leaves two open issues不幸的是,这仍然留下两个悬而未决的问题

a) this code adds {"newkey": "newValue"} to all children where the search criteria is true, ie: to both id:ddd && id:zzz , rather than to just the id:ddd record 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) adding multiple section criteria to the any clause. b) 向any子句添加多个部分标准。 I have tried using the AND or |我曾尝试使用AND| joining methods but this throws errors.加入方法,但这会引发错误。

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

Can you advise the syntax for both issues.你能建议这两个问题的语法吗?

UPDATE2 Understanding the when filter a littler better, I have now nested these and it seems to work in narrowing the result set. UPDATE2更好地理解when过滤器,我现在已经嵌套了这些,它似乎可以缩小结果集。 However problem a) updating both records when a match is true still exists.但是问题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"
        }]
    }
}

Here is a response to the "UPDATED" question:这是对“更新”问题的回答:

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

ps ps

In future, please follow the mcve guidelines: http://stackoverflow.com/help/mcve将来,请遵循 mcve 指南: http ://stackoverflow.com/help/mcve

The simplest way to use walk here is to include the update in the "then" part of the if ... then ... else ...end .在这里使用walk的最简单方法是将更新包含在if ... then ... else ...end的“then”部分中。 To emphasize and clarify this, and to shorten the solution, I'll use the generic helper function, when :为了强调和澄清这一点,并缩短了解决方案,我将使用通用的辅助功能, when

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

The solution to the problem can now be written in a very straightforward way:现在可以用非常简单的方式编写问题的解决方案:

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

Of course you might want a fancier test than .id == "ddd", and you might want to perform the update only once per "ccc" object, but the same structure would be used.当然,您可能需要比 .id == "ddd" 更高级的测试,并且您可能希望每个 "ccc" 对象只执行一次更新,但将使用相同的结构。

In reality, you might also want to wrap the above expression in a def so it can more readily be parameterized and maintained.实际上,您可能还想将上述表达式包装在def以便更容易地对其进行参数化和维护。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM