JQ:将对象数组减少为对象,添加到数组

时间:2016-10-12 09:05:40

标签: arrays json addition jq

我有一个更复杂的JQ表达式来处理一个对象数组。

输入如下:

[
    { "key": "1", "value": "value 1"},
    { "key": "2", "value": "value 2"},
    { "key": "1", "value": "value 3"},
]

我想得到的是:

{
    "1": { "values": ["value 1", "value 3"] },
    "2": { "values": ["value 2"] }
}

或者,对于我的用例:

{
    "1": [ "value 1", "value 3" ],
    "2": [ "value 2" ]
}

也没关系。

我已经尝试过使用… | { (.key): [.value] },但结果是(对我来说并不感到惊讶)以后出现的密钥只会覆盖现有密钥。我想要完成的事情就像"创建一个新的键/值对或将.value添加到已经存在的一个'值'阵列"

2 个答案:

答案 0 :(得分:2)

好的,在最终找到我想要的东西之后,我也明白我之前的过滤器没有保留输入数组但导致对象相继输出。所以这基本上就是为什么我发现的所有例子都不起作用的原因。

我想按键分组(因此键/值要求),group_by已经这样做了,但是不会工作。

从分组工作只需要一小步到我的解决方案(唯一键,数组中的值)。

'… group_by(.key) | map({ "key": .[0].key, "values": map(.value) | unique })'

输出现在看起来像这样,这完全可以满足我的要求:

[
    {
        "key": "1",
        "values": [
            "value 1",
            "value 3"
        ],
    },
    {
        "key": "2",
        "values": [
            "value 2"
        ]
    }
]

答案 1 :(得分:2)

依赖group_by的解决方案的缺点是group_by需要排序,这在此是不必要的。在这个响应中,我将展示如何通过使用一个通用的(通常是有用的)jq函数来避免任何排序,该函数“混合”一组JSON对象,主要是通过将每个键的值弹出到一个数组中,然后连接相应的阵列。

# input should be an array of objects def meld: reduce .[] as $o ({}; reduce ($o|keys)[] as $key (.; .[$key] += [$o[$key]] ));

我们还定义一些数据: def data: [ { "key": "1", "value": "value 1"}, { "key": "2", "value": "value 2"}, { "key": "1", "value": "value 3"} ] ;

然后是过滤器:

 data |  map([.] | from_entries) | meld

产生

{"1":["value 1","value 3"],"2":["value 2"]}