【问题标题】:Merge two complex JSON objects (using jq)合并两个复杂的 JSON 对象(使用 jq)
【发布时间】:2017-10-19 17:03:33
【问题描述】:

我正在尝试替换复杂 JSON 对象中的对象。似乎jq 工具可以提供完美的解决方案,但我真的在为正确的选择/过滤器链而苦苦挣扎。

我有一个完整的配置 JSON 对象,看起来像这样(里面有更多的键,为了说明而缩短了它):

{
    "some-array": [
        {
            "name": "foo",
            "attr": "value"
        },
        {
            "name": "foo bar",
            "attr": "value"
        },
        {
            "name": "foo bar baz",
            "attr": "value"
        }
    ],
    "some-other-array": []
}

现在我有另一个对象,其中包含一个包含更新对象的数组,我需要以某种方式与完整配置合并。我需要按名称查找嵌套对象,如果不存在则添加它,如果存在则替换它。

{
    "some-array": [
        {
            "name": "foo",
            "attr": "new-value",
            "new-attrib": "new-value"
        },
        {
            "name": "foo bar",
            "attr": "new-value"
        }
    ]
}

所以,对于上面的例子,我的预期结果是:

{
    "some-array": [
        {
            "name": "foo",
            "attr": "new-value",
            "new-attrib": "new-value"
        },
        {
            "name": "foo bar",
            "attr": "new-value"
        },
        {
            "name": "foo bar baz",
            "attr": "value"
        }
    ],
    "some-other-array": []
}

我已经尝试过 select(."some-array"[].name == "foo") 和其他一些东西作为 jq 过滤器,但我在这里努力前进,非常感谢一些灵感/实际解决方案。

谁能告诉我jq 是否真的可以实现我想要实现的目标,还是我必须找到其他解决方案?

【问题讨论】:

    标签: json object merge jq


    【解决方案1】:

    是的,这是可能的,事实上,在对问题的各种解释下,这很容易。

    以下解决了最初陈述的问题,“it”被解释为.["some-array"],而不是它的组成部分。

    假设$update 持有带有更新信息的对象,如图所示,可以使用此过滤器执行更新:

    .["some-array"] = ($update | .["some-array"])
    

    有很多方法可以赋予$update 所需的价值。

    【讨论】:

    • 非常感谢您的快速回答,但我无法让您的解决方案发挥作用。我试过cat example.json | jq --slurpfile update example-update.json '.["some-array"] = ($update | .["some-array"])',我得到jq: error (at <stdin>:17): Cannot index array with string "some-array"。和--slurpfile有关系吗?
    • 之后我尝试了--argfile 而不是--slurpfile,这已经非常接近解决方案了,但实际上它并没有扩展"some-array",而是替换了数组的内容,这不是我想要的想要。
    • @zwerch - 你写了“如果它不存在就添加它,如果它存在就替换它”。也许你应该显示预期的结果。关于--slurpfile,请阅读jq手册。
    • 抱歉造成误会。感谢您的帮助,我添加了预期的结果。
    【解决方案2】:

    这是更新后问题的解决方案。此解决方案假定名称是字符串值的。它依赖于两个辅助函数:

    # array-to-hash
    def a2h(f): reduce .[] as $x ({}; . + {($x | f): $x});
    
    # hash-to-array
    def h2a: . as $in | reduce keys_unsorted[] as $k ([]; . + [$in[$k]]);
    

    第一个基于输入数组创建“哈希”,第二个实现逆运算。

    使用这些辅助函数,可以编写解决方案:

    .["some-array"] |= (a2h(.name) + ($update|.["some-array"] | a2h(.name)) | h2a)
    

    其中$update 是“新”值。该解决方案依赖于对象加法的“右支配”。

    输出

    对于给定的示例,输出为:

    {
      "some-array": [
        {
          "name": "foo",
          "attr": "new-value",
          "new-attrib": "new-value"
        },
        {
          "name": "foo bar",
          "attr": "new-value"
        },
        {
          "name": "foo bar baz",
          "attr": "value"
        }
      ],
      "some-other-array": []
    }
    

    【讨论】:

      猜你喜欢
      • 2021-07-21
      • 2019-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-11
      相关资源
      最近更新 更多