代码之家  ›  专栏  ›  技术社区  ›  art vanderlay

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

  •  1
  • art vanderlay  · 技术社区  · 8 年前

    不太清楚如何清楚地提出这个问题,但给出如下递归结构。我将如何使用 walk 将两个或多个键字符串与值匹配。我不知道结果会在结构中的什么位置。它可以是最高层,也可以是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=ccc 然后,我想向该记录添加一个新的键/值。使用 .key|match("") 将给我一个与键的值匹配的值,但不是键名称本身。所以正在搜索 ddd 可能两者都匹配 id other

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

    match\u标准

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

    新建\u key\u值

    += {"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
    

    你能告诉我这两个问题的语法吗。

    更新2 了解 when 过滤稍微好一点,我现在嵌套了这些,它似乎可以缩小结果集。然而,问题 a) 当匹配为true时仍存在更新这两个记录。

    jsonOut=$(jq 'walk(when(type == "object";
              with_entries(
                           when(any(.value[]; .id == "ddd");
                            when(any(.value[]; .other == "zzz");
                                .value[] += {"newkey": "newValue"}
                                )))))' <<< ${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"
            }]
        }
    }
    
    2 回复  |  直到 8 年前
        1
  •  1
  •   peak    8 年前

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

    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

        2
  •  0
  •   peak    8 年前

    最简单的使用方法 walk 以下是将更新包含在 if ... then ... else ...end 。为了强调和澄清这一点,并缩短解决方案,我将使用通用助手函数, 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 因此,可以更容易地对其进行参数化和维护。

    推荐文章