我正在shell脚本中使用jq工具(jq-json-processor)来解析json。
我有2个json文件,想将它们合并为一个唯一的文件
在这里文件的内容:
文件1:
{"tag_id" : ["t1"], "inst_id" : "s1"}
{"tag_id" : ["t1"], "inst_id" : "s2"}
文件2:
{"tag_id" : ["t2"], "inst_id" : "s1"}
{"tag_id" : ["t2"], "inst_id" : "s2"}
{"tag_id" : ["t2"], "inst_id" : "s3"}
预期结果:
{"tag_id" : ["t1","t2"], "inst_id" : "s1"}
{"tag_id" : ["t1","t2"], "inst_id" : "s2"}
{"tag_id" : ["t2"], "inst_id" : "s3"}
答案 0 :(得分:1)
一种方法是使用group_by
:
jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json -f merge.jq
merge.jq包含:
def sigma(f): reduce f as $x (null; . + $x);
$file1 + $file2
| group_by(.inst_id)[]
| {tag_id: sigma(.[].tag_id), inst_id: .[0].inst_id }
答案 1 :(得分:0)
这是一种类似联接的方法。假定您的jq具有INDEX/2
并支持--slurpfile
命令行选项。如果您的jq不具备这些功能,尽管有一些简单的解决方法,但现在将是升级的好时机。
jq -n --slurpfile file1 file1.json -f join.jq file2.json
def join(s2; joinField; field):
INDEX(.[]; joinField)
| reduce s2 as $x (.;
($x|joinField) as $key
| if .[$key] then (.[$key]|field) += ($x|field)
else .[$key] = $x
end )
| .[]
;
$file1 | join(inputs; .inst_id; .tag_id)
答案 2 :(得分:0)
以下方法非常有效:
(a)利用了file1.json和file2.json是对象流这一事实,从而避免了将这些对象存储为数组所需的内存;
(b)它避免了排序(例如,group_by
导致的排序)
关键概念是对象的键式添加。为了在流中执行对象的键式添加,我们定义以下通用函数:
# s is assumed to be a stream of mutually
# compatible objects in the sense that, given
# any key of any object, the values at that key
# must be compatible w.r.t. `add`
def keywise_add(s):
reduce s as $x ({};
reduce ($x|keys_unsorted)[] as $k (.;
.[$k] += $x[$k]));
任务现在可以如下完成:
keywise_add(inputs | {(.inst_id): .tag_id} )
| keys_unsorted[] as $k
| {tag_id: .[$k], inst_id: $k}
在add.jq中使用上述程序,调用:
jq -c -n -f add.jq file1.json file2.json
产量:
{"tag_id":["t1","t2"],"inst_id":"s1"}
{"tag_id":["t1","t2"],"inst_id":"s2"}
{"tag_id":["t2"],"inst_id":"s3"}
以上假设inst_id
是字符串值。如果不是这种情况,那么只要inst_id|tostring
之间没有冲突,就可以使用上述方法,例如inst_id
始终是数字的情况。>