使用jq从多个文件聚合json数组,按键分组

时间:2020-08-05 12:12:52

标签: json jq

我想将两个或多个文件聚合到一个json中,并在同一键下聚合数组。

file1.json

{
  "shapes": [
    {
      "id": "1",
      "name": "circle"
    },
    {
      "id": "2",
      "name": "square"
    }
  ]
}

file2.json

{
  "shapes": [
    {
      "id": "3",
      "name": "triangle"
    }
  ]
}

预期结果:

{
  "shapes": [
    {
      "id": "1",
      "name": "circle"
    },
    {
      "id": "2",
      "name": "square"
    },
    {
      "id": "3",
      "name": "triangle"
    }
  ]
}

我可以使用以下jq命令执行此操作:

jq -s '{shapes: map(.shapes)|add }' file*.json

但这需要我知道 shapes 属性并对其进行硬编码。有没有简单的方法,我无需显式使用键名就能得到相同的结果?

3 个答案:

答案 0 :(得分:1)

这是一个解决方案,它也解决了一个更一般的问题:首先,它可以任意处理许多输入文件;第二,假设每个顶级键都是数组值,它就为每个键按键形成“求和”。

通用函数:

  # the values at each key are assumed to be arrays
  def aggregate(stream): 
    reduce stream as $o ({}; 
      reduce ($o|keys_unsorted[]) as $k (.; 
        .[$k] += $o[$k] ));

为避免“拖拉”,我们将使用inputs

aggregate(inputs)

因此,调用必须使用-n命令行选项:

jq -n -f program.jq *.json

答案 1 :(得分:1)

这是一个适用于每个顶级对象只有一个键的解决方案,它既高效又概念简单。假定使用-n选项调用了jq。

reduce inputs as $in (null;
   ($in|keys_unsorted[0]) as $k | { ($k): (.[$k] + $in[$k]) })

或更紧凑:

reduce inputs as $in (null; ($in|keys_unsorted[0]) as $k | .[$k] += $in[$k] )

答案 2 :(得分:0)

尝试以下代码。这可以处理任意数量的文件。假定所有输入都是json对象,其中所有值都作为数组。所有此类数组在按键分组后进行汇总。它输出一个对象,该对象的键与对应的聚合数组关联。

jq -s 'map(to_entries)|add|group_by(.key)|
    map( { "key": (.[0].key), "value": (map(.value)|add)})|
    from_entries' file1.json file2.json

对于您的示例输入,它给出:

{
  "shapes": [
    {
      "id": "1",
      "name": "circle"
    },
    {
      "id": "2",
      "name": "square"
    },
    {
      "id": "3",
      "name": "triangle"
    }
  ]
}