JQ:如果某些键值相同则合并条目

Goo*_*oot 3 merge json object jq

我想将 json 文件的条目与 jq 合并。

如果某些定义的键的值匹配,我想合并条目。不匹配的数据应存储在数组中。
我为此案例提供了一些 JSON 示例。

如果街道和门牌号相同,我想合并此条目并将“member”的值放入数组中。

匹配键:门牌号+街道必须相同。

输入示例

[{
 "street"  : "Foobar ave",
 "housenumber": 4,
 "member":"Carl"
 },
 {
 "street"  : "Foobar ave",
 "housenumber": 4,
 "member":"Bernd"
 },
 {
 "street"  : "Foobar ave",
 "housenumber": 2,
 "member":"Ann"
 }]
Run Code Online (Sandbox Code Playgroud)

目标结果:

[{
 "street"  : "Foobar ave",
 "housenumber": 4,
 "members":["Carl","Bernd"]
 },
 {
 "street"  : "Foobar ave",
 "housenumber": 2,
 "members":["Ann"]
 }]
Run Code Online (Sandbox Code Playgroud)

pea*_*eak 5

下面使用GROUPS_BY用 JQ 解析 JSON 行中定义的通用且高效的版本来按顺序翻转键值

GROUPS_BY是内置的一个高效版本group_by,您也可以使用它,如下所示。)

GROUPS_BY是面向流的。GROUPS_BY因此,解决当前问题的“自然”用途是:

  GROUPS_BY(.[]; [.street, .housenumber])
  | (.[0]|del(.member)) + { members: (map(.member)) }
Run Code Online (Sandbox Code Playgroud)

这会生成“组”流,同时保留“成员”的顺序:

{"street":"Foobar ave","housenumber":4,"members":["Carl","Bernd"]}
{"street":"Foobar ave","housenumber":2,"members":["Ann"]}
Run Code Online (Sandbox Code Playgroud)

如果你要求结果是一个数组,那么只需将上面的两行程序用方括号括起来: [ .... ]

使用内置的解决方案group_by

目前,group_by使用排序算法,这意味着“成员”的顺序可能不会被保留:

group_by( [.street, .housenumber])
| map((.[0]|del(.member)) + { members: (map(.member)) })
Run Code Online (Sandbox Code Playgroud)

使用 melds_by/2 的通用解决方案

给定一个对象流和分组标准 f,melds_by会发出以下形式的对流:

 [groupid, melded_object]
Run Code Online (Sandbox Code Playgroud)

其中melded_object是由“groupid”组中的对象构造的对象,该组中存在所有键,每个键的值是相应值的数组:

def melds_by(stream; f):
  GROUPS_BY(stream; f)
  | . as $in
  | [ (.[0]|f),
      reduce (add|keys[]) as $k ({}; .[$k] = [$in[] | .[$k]]) ]
  ;
Run Code Online (Sandbox Code Playgroud)

为了将原始问题的解作为单个数组获得,我们可以简单地编写:

[ melds_by(.[]; {street, housenumber})
  | .[1] + .[0]
  | with_entries(.key |= if . == "member" then "members" else . end) ]
Run Code Online (Sandbox Code Playgroud)

上面的最后一行只是重命名“member”键。