如何在jq中实现对象减法操作?
用jq实现递归反向移除(类似反向meld操作)
我们知道可以用jq的*运算符递归合并两个对象,比如执行:
jq '.[0] * .[1]' -s a.json b.json
但这个方法无法合并数组,不过已有对应的解决思路。现在需要实现相反的操作:从a.json中移除所有在b.json里存在的内容(已知b.json的所有内容都存在于a.json中)。
示例数据
a.json
{ "background": { "service_worker": "js/background.js", "type": "module" }, "manifest_version": 3, "permissions": [ "storage", "unlimitedStorage" ] }
b.json
{ "background": { "type": "module" }, "permissions": [ "unlimitedStorage" ] }
预期结果
{ "background": { "service_worker": "js/background.js" }, "manifest_version": 3, "permissions": [ "storage" ] }
通用解决方案
可以定义一个递归的jq函数remove来实现这个逻辑,兼容嵌套对象和数组处理:
def remove($b): if type == $b.type then if type == "object" then reduce keys[] as $k ({}; if ($b | has($k)) then ($[$k] | remove($b[$k])) as $val | if $val | (type == "object" and length > 0) or (type == "array" and length > 0) or (type | IN("string","number","boolean","null")) then . + {($k): $val} else . end else . + {($k): $[$k]} end ) elif type == "array" then [.[] as $item | if $b | index($item) then empty else $item end] else if . != $b then . else empty end end else . end;
使用方法
执行以下命令,将b.json作为参数传入处理a.json:
jq --argfile b b.json 'remove($b)' a.json
逻辑说明
- 对象处理:遍历原对象的每个键,若对比对象(b)中存在该键,则递归处理对应的值;只有当处理后的值为非空对象、非空数组,或是与b中值不同的基本类型时,才保留该键。
- 数组处理:过滤掉原数组中所有在对比数组(b)里存在的元素。
- 基本类型:若原值与b中的值相同则移除,否则保留。
内容的提问来源于stack exchange,提问作者kaya51
相关产品推荐
相关产品推荐

