如何用JQ查询更新两层嵌套数组属性,兼容空JSON结构?
用JQ更新/插入JSON层级结构中的count值
我已经花了两天时间解决这个问题,但一直没找到合适的方法。
示例JSON
{ "items": [ { "name":"itemA", "bins":[ { "bin_id":"b1", "count":"11" }, { "bin_id":"b2", "count":"22" } ] }, { "name":"itemB", "bins":[ { "bin_id":"b5", "count":"55" } ] } ] }
重要说明
- 输入JSON可能是空对象
{},也可能缺失部分层级结构
需求
根据输入的itemName、binId和新的count值,要么插入完整的层级结构,要么更新对应count字段的值。比如针对itemA、b1,需要将.items -> 名称为itemA的项 -> bin_id为b1的bin -> count设置为68。
尝试过程
我试过用INDEX访问items,这部分可行,但没法进一步访问bins并更新最终的count值。
后来我写出了下面的JQ语句,但看起来非常繁琐,想知道有没有更清晰的实现方式:
.items |= [INDEX(.[]?;.name) | .itemA |= .+ {name:"itemA",bins:[INDEX(.bins[]?;.bin_id) | .b1 |= .+ {bin_id:"b1",count:"188000"} | .[]]} | .[]]
优化后的JQ实现
可以利用JQ的INDEX、//(默认值)和模块化逻辑来简化代码,同时完美处理缺失层级的情况。假设通过--arg传入参数$itemName、$binId、$newCount,脚本如下:
.items |= ( # 将items数组转为以name为键的索引对象 INDEX(.[]?; .name) as $itemsIndex # 获取目标item,不存在则创建默认结构 | ($itemsIndex[$itemName] // {name: $itemName, bins: []}) as $targetItem # 处理目标item的bins层级 | ( INDEX($targetItem.bins[]?; .bin_id) as $binsIndex # 获取目标bin,不存在则创建默认结构,更新count值 | ($binsIndex[$binId] // {bin_id: $binId}) | .count = $newCount | $binsIndex[$binId] = . # 转回bins数组 | [$binsIndex[]] | $targetItem.bins = . ) # 更新items索引对象,再转回数组 | $itemsIndex[$itemName] = $targetItem | [$itemsIndex[]] )
使用示例
比如要更新itemA的b1对应的count为68,执行命令:
jq --arg itemName "itemA" --arg binId "b1" --arg newCount "68" '上述脚本内容' input.json
这个写法逻辑分层清晰,能自动处理空JSON、缺失目标item、缺失目标bin等所有边界情况,比你之前的实现简洁易读得多。
内容的提问来源于stack exchange,提问作者Hooch
相关产品推荐
相关产品推荐

