I have two JSON files of the form:
{
"xFruits": {
"views": 163,
"all": {
"xApples": {
"views": 28,
"eats": 10,
"discards": 17
}
}
},
"xVegetables": {
"views": 134,
"all": {
"xBeans": {
"views": 29,
"eats": 11,
"discards": 14
},
"xCarrots": {
"views": 30,
"eats": 12,
"discards": 11
},
}
},
}
Keys starting with x
change names and vary in number. The others are fixed. Most x
keys exist in both files, but some may exist only in file 1 and others only in file 2.
I want to use jq
to merge both files and add numbers when have the same path. So if this is the second file:
{
"xFruits": {
"views": 16,
"all": {
"xApples": {
"views": 2,
"eats": 2,
"discards": 5
}
}
},
"xVegetables": {
"views": 147,
"all": {
"xBeans": {
"views": 12,
"eats": 7,
"discards": 13
},
"xSpinach": {
"views": 30,
"eats": 12,
"discards": 11
},
}
},
}
The the mix of both would result in:
{
"xFruits": {
"views": 179,
"all": {
"xApples": {
"views": 30,
"eats": 12,
"discards": 22
}
}
},
"xVegetables": {
"views": 281,
"all": {
"xBeans": {
"views": 41,
"eats": 18,
"discards": 27
},
"xCarrots": {
"views": 30,
"eats": 12,
"discards": 11
},
"xSpinach": {
"views": 30,
"eats": 12,
"discards": 11
},
}
},
}
Note how xCarrots
and xSpinach
retained their original values because each only existed in one file, while all other values were added together.
Is this something jq
is capable of?
You could iterate over a stream of path-value arrays using tostream
and reduce
, and successively build up the result object using getpath
, setpath
and simple addition. Initially non-existent paths evaluate to null
, which for the addition acts as 0
.
jq -n '
reduce (inputs | tostream | select(has(1))) as [$p,$v]
(null; setpath($p; getpath($p) + $v))
' file1.json file2.json
{
"xFruits": {
"views": 179,
"all": {
"xApples": {
"views": 30,
"eats": 12,
"discards": 22
}
}
},
"xVegetables": {
"views": 281,
"all": {
"xBeans": {
"views": 41,
"eats": 18,
"discards": 27
},
"xCarrots": {
"views": 30,
"eats": 12,
"discards": 11
},
"xSpinach": {
"views": 30,
"eats": 12,
"discards": 11
}
}
}
}