jq合并多个json文件合并任意数组元素
我想使用jq合并多个文件,如果多个文件包含一个名称为的数组,我需要合并数组(顺序无关紧要) 比如说 文件1 文件2 建议其他堆栈溢出文章合并这些json,我应该做:jq合并多个json文件合并任意数组元素,json,jq,Json,Jq,我想使用jq合并多个文件,如果多个文件包含一个名称为的数组,我需要合并数组(顺序无关紧要) 比如说 文件1 文件2 建议其他堆栈溢出文章合并这些json,我应该做: jq -s '.[0] * .[1]' file1 file2 但这让我明白: { "value1": 200, "timestamp": 1382461861, "parameter": [ { "param": 2 } ], "status": 200, "value": {
jq -s '.[0] * .[1]' file1 file2
但这让我明白:
{
"value1": 200,
"timestamp": 1382461861,
"parameter": [
{
"param": 2
}
],
"status": 200,
"value": {
"aaa": {
"value3": "v3",
"value4": 4
}
}
}
我想要的是:
{
"value1": 200,
"timestamp": 1382461861,
"parameter": [
{ "param": 1},
{ "param": 2}
],
"status": 200,
"value": {
"aaa": {
"value3": "v3",
"value4": 4
}
}
}
请注意,“parameter”数组应该包含file1和file2中的元素
我还需要一个解决方案,它不需要指定数组中的字段,而且数组可以嵌套在json的任何级别
我愿意接受一个不使用jq的解决方案,我想一个小的python脚本就可以了
我找到的最接近的解决方案要求我知道参数是数组
jq -s '.[0] * .[1]' file1.json file2.json >temp.json
jq -s '.[0].parameter=([.[].parameter]|flatten)|.[0]' temp.json file1.json
输出是
{
"value1": 200,
"timestamp": 1382461861,
"parameter": [
{
"param": 2
},
{
"param": 1
}
],
"status": 200,
"value": {
"aaa": {
"value3": "v3",
"value4": 4
}
}
}
您基本上是在实施自己的合并方案。如果您想要一个通用的解决方案,那么您需要定义一个函数,这样它就可以递归地完成。这与“
*
不同,但具有不同的数组语义”,但您可以使用如下内容:
def new_merge($item):
if type == ($item|type) then # if same types
if type == "array" then # concatenate the arrays
. + $item
elif type == "object" then # recursively merge objects
reduce ($item|to_entries[]) as {$key,$value} (.;
.[$key] |= new_merge($value)
)
else # just take the "other" value
$item // .
end
else # just take the "other" value
$item // .
end
;
$ jq 'reduce inputs as $i (.; do_merge($i))' file*.json
{
"value1": 200,
"timestamp": 1382461861,
"parameter": [
{
"param": 1
},
{
"param": 2
}
],
"status": 200,
"value": {
"aaa": {
"value3": "v3",
"value4": 4
}
}
}
我会把它放在你的~/.jq
文件中,然后像这样调用:
def new_merge($item):
if type == ($item|type) then # if same types
if type == "array" then # concatenate the arrays
. + $item
elif type == "object" then # recursively merge objects
reduce ($item|to_entries[]) as {$key,$value} (.;
.[$key] |= new_merge($value)
)
else # just take the "other" value
$item // .
end
else # just take the "other" value
$item // .
end
;
$ jq 'reduce inputs as $i (.; do_merge($i))' file*.json
{
"value1": 200,
"timestamp": 1382461861,
"parameter": [
{
"param": 1
},
{
"param": 2
}
],
"status": 200,
"value": {
"aaa": {
"value3": "v3",
"value4": 4
}
}
}
另一方面,如果您希望像原始问题中那样递归合并数组项,只需将数组大小写更改为递归合并相应的项即可
def new_merge2($item):
if type == ($item|type) then
if type == "array" then
[.,$item] | transpose[] as [$a,$b] | [$a | new_merge2($b)]
elif type == "object" then
reduce ($item|to_entries[]) as {$key,$value} (.;
.[$key] |= new_merge2($value)
)
else
$item // .
end
else
$item // .
end
;
这一版本将产生:
{
"value1": 200,
"timestamp": 1382461861,
"parameter": [
{
"param1": 1,
"param2": 2
}
],
"status": 200,
"value": {
"aaa": {
"value3": "v3",
"value4": 4
}
}
}
这里是一个解决问题的方法,在这种情况下,有两个文件,每个文件都有一个对象,其中在某个级别上至少有一个相同的命名数组值字段 许多方面的要求都不明确,因此以下可能需要根据更详细的要求进行调整。如果有两个以上的文件,则可以使用相同的技术,但细节将取决于详细的需求
jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json '
# a and b are expected to be jq paths ending with a string
# emit the array of the intersection of key names
def common(a;b):
((a|map(.[-1])) + (b|map(.[-1])))
| unique;
$file1[0] as $f1
| $file2[0] as $f2
| [$f1 | paths as $p | select(getpath($p) | type == "array") | $p] as $p1
| [$f2 | paths as $p | select(getpath($p) | type == "array") | $p] as $p2
| $f1+$f2
| if ($p1|length) > 0 and ($p2|length) > 0
then common($p1; $p2) as $both
| if ($both|length) > 0
then first( $p1[] | select(.[-1] == $both[0])) as $p1
| first( $p2[] | select(.[-1] == $both[0])) as $p2
| ($f1 | getpath($p1)) as $a1
| ($f2 | getpath($p2)) as $a2
| setpath($p1; $a1 + $a2)
else .
end
else .
end
'
jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json '
$file1[0] as $f1
| $file2[0] as $f2
| reduce ($f1 | paths) as $p ($f1+$f2;
($f1|getpath($p)) as $v1
| ($f2|getpath($p)) as $v2
| if ($v1 | type == "array") and
($v2 | type == "array")
then setpath($p; $v1 + $v2)
else .
end)
'
输出
使用给定输入,在第二个文件中添加缺少的“:”后,输出为:
{
"value1": 200,
"timestamp": 1382461861,
"parameter": [
{
"param1": 1
},
{
"param2": 2
}
],
"status": 200,
"value": {
"aaa": {
"value3": "v3",
"value4": 4
}
}
}
对于两个文件(每个文件有一个对象)的情况,下面是一个简单但通用的解决方案 此解决方案将在同一路径上连接每对数组。希望它足够简单,可以为自己说话,并且可以进行修改以处理范围更广、更详细的需求
jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json '
# a and b are expected to be jq paths ending with a string
# emit the array of the intersection of key names
def common(a;b):
((a|map(.[-1])) + (b|map(.[-1])))
| unique;
$file1[0] as $f1
| $file2[0] as $f2
| [$f1 | paths as $p | select(getpath($p) | type == "array") | $p] as $p1
| [$f2 | paths as $p | select(getpath($p) | type == "array") | $p] as $p2
| $f1+$f2
| if ($p1|length) > 0 and ($p2|length) > 0
then common($p1; $p2) as $both
| if ($both|length) > 0
then first( $p1[] | select(.[-1] == $both[0])) as $p1
| first( $p2[] | select(.[-1] == $both[0])) as $p2
| ($f1 | getpath($p1)) as $a1
| ($f2 | getpath($p2)) as $a2
| setpath($p1; $a1 + $a2)
else .
end
else .
end
'
jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json '
$file1[0] as $f1
| $file2[0] as $f2
| reduce ($f1 | paths) as $p ($f1+$f2;
($f1|getpath($p)) as $v1
| ($f2|getpath($p)) as $v2
| if ($v1 | type == "array") and
($v2 | type == "array")
then setpath($p; $v1 + $v2)
else .
end)
'
输出完全符合要求,假设第二个文件已以明显的方式更正,因此它是有效的JSON。similar@AC-请澄清要求,特别是如果有两个以上的文件。因此,通过“合并”数组,您的意思是获取相应的项并合并它们?仅合并两个文件。我希望将数组元素附加到数组中。通过编辑我的示例,我澄清了数组中的两个元素具有相同的键。因此,基本上,您希望获得oguz ismail链接的语义?连接数组?