【问题标题】:Merge two complex JSON objects with arrays将两个复杂的 JSON 对象与数组合并
【发布时间】:2019-01-22 10:31:47
【问题描述】:

我有以下两个 json 作为输入:

{
  "one": {
    "vars": [
      {
        "name": "a",
        "value": "a"
      },
      {
        "name": "b",
        "value": "b"
      }
    ]
  },
  "two": {
    "vars": [
      {
        "name": "c",
        "value": "c"
      },
      {
        "name": "d",
        "value": "d"
      }
    ]
  },
  "extras": "whatever"
}
{
  "one": {
    "vars": [
      {
        "name": "e",
        "value": "e"
      },
      {
        "name": "f",
        "value": "f"
      }
    ]
  },
  "two": {
    "vars": [
      {
        "name": "g",
        "value": "g"
      },
      {
        "name": "h",
        "value": "h"
      }
    ]
  }
}

我想合并它们以获得以下结果,其中每个部分的每个 vars 数组都合并在一起:

{
  "one": {
    "vars": [
      {
        "name": "a",
        "value": "a"
      },
      {
        "name": "b",
        "value": "b"
      },
      {
        "name": "e",
        "value": "e"
      },
      {
        "name": "f",
        "value": "f"
      }
    ]
  },
  "two": {
    "vars": [
      {
        "name": "c",
        "value": "c"
      },
      {
        "name": "d",
        "value": "d"
      },
      {
        "name": "g",
        "value": "g"
      },
      {
        "name": "h",
        "value": "h"
      }
    ]
  },
  "extras": "whatever"
}

理想但不是强制性的:

  • 键(此处为 onetwo)是任意的,并且可能存在未定义的数量。
  • vars 数组不会包含重复项(基于 name),并且将应用正确的优先级来覆盖第一个数组中的值。

我设法用以下命令合并了这两个对象和只有一个数组,但是密钥是硬编码的,我有点卡住了:

jq -s '.[0].one.vars=([.[].one.vars]|flatten)|.[0]' file1.json file2.json

【问题讨论】:

    标签: json merge jq


    【解决方案1】:

    首先,这是一个忽略顶级键名但不尝试避免重复的解决方案:

    $A
    | reduce keys_unsorted[] as $k (.;
        if .[$k] | (type == "object") and has("vars")
        then (.[$k]|.vars) += ($B[$k]|.vars) else . end )
    

    这里当然 $A 和 $B 指的是两个对象。您可以通过多种方式设置 $A 和 $B。

    如果您想重新排序顶级键,您可以简单地使用指定顺序的过滤器扩展上述内容,例如:{extras, two, one}

    为避免重复,我建议编写一个辅助函数来做到这一点,如下节所示。

    避免重复

    def extend(stream):
      reduce stream as $s (.;
        (map(.name) | index($s|.name)) as $i
        | if $i then .[$i] += $s
          else . + [$s]
          end) ;
    
    
    $A
    | reduce keys_unsorted[] as $k (.;
        if .[$k] | (type == "object") and has("vars")
        then (.[$k].vars) = ( .[$k].vars | extend(($B[$k].vars[])))
        else . end
      )
    

    【讨论】:

      【解决方案2】:
      jq -n 'input as $b | input
      | .one.vars |= . + $b.one.vars
      | .two.vars |= . + $b.two.vars' file2.json file1.json
      

      file1.json 必须在file2.json 之后才能保留extras

      【讨论】:

      • 任何关于如何使键和顺序任意的想法?
      • @aaaaaahaaaaa 抱歉,不知道。
      猜你喜欢
      • 2019-08-27
      • 1970-01-01
      • 2017-10-19
      • 2012-05-28
      • 2018-05-24
      • 1970-01-01
      • 1970-01-01
      • 2019-08-31
      • 1970-01-01
      相关资源
      最近更新 更多