如何使用jq合并json文件?

时间:2019-01-17 09:29:47

标签: json jq

我正在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"}

3 个答案:

答案 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

join.jq

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始终是数字的情况。