使用jq合并两个JSON文件并对相同路径整数求和
用JQ合并两个JSON文件并对同路径整数值求和
我有两个结构相似的JSON文件,其中以x开头的键名称可变且数量不定,其他键(如views、all)固定。大部分x开头的键在两个文件中都存在,但部分仅存在于其中一个文件。我需要合并这两个文件,并对相同路径的整数值进行求和,仅在单个文件中存在的键则保留原值。
示例输入文件
文件1:
{ "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 } } } }
文件2:
{ "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 } } } }
期望合并结果
{ "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 } } } }
解决方案:用JQ实现
完全可以用JQ实现这个需求,核心思路是递归合并两个JSON对象,遇到数值类型时求和,遇到对象类型时继续递归合并,键不存在时直接保留现有值。
简化递归版命令
假设两个文件分别名为file1.json和file2.json,运行以下命令:
jq -s ' def merge_sum($a; $b): ($a | type) as $atype | ($b | type) as $btype | if $atype == "object" and $btype == "object" then ($a + $b) | reduce keys[] as $k (.; .[$k] = merge_sum($a[$k]; $b[$k]) ) elif $atype == "number" and $btype == "number" then $a + $b else $b // $a end; reduce .[] as $item ({}; merge_sum(.; $item)) ' file1.json file2.json
逻辑解释
-s:将输入的多个JSON文件读入一个数组中- 自定义递归函数
merge_sum:- 若两个值都是对象:合并键集合后,对每个键递归执行合并逻辑
- 若两个值都是数值:直接求和
- 其他情况:保留存在的那个值(优先取第二个文件的值,若不存在则取第一个)
- 外层
reduce:遍历数组中的每个文件对象,逐步合并到初始空对象中
这个版本能自动处理任意深度的JSON结构,扩展性更强,逻辑也更清晰。
内容的提问来源于stack exchange,提问作者user137369
相关产品推荐
相关产品推荐

