求助:基于部分匹配过滤JSON数组元素的jq查询编写
问题需求
编写jq查询,过滤places[].fThings[]或places.sThings[]中与toDo[]内字符串无部分匹配的元素,需满足:
- 部分
places对象可能不含fThings/sThings,或仅含其一、二者都有 - 输出保留原JSON结构,仅移除不匹配的*Things元素,空数组可保留
- 此前尝试
map(select(any(index(...))))及contains组合时,频繁触发"Cannot index"或"Cannot iterate"错误
解决方案
核心思路
先提取toDo元素的匹配前缀(*Things元素是对应toDo元素的前缀,比如pcs_app#2.1#bp对应toDo中的pcs_app#2.1#bp##2.1-2410.0-05),再对每个place对象的fThings/sThings做过滤,同时通过字段存在性判断避免索引报错。
完整jq命令
[.toDo[] | split("##")[0]] as $matchPrefixes | .places |= map( (if has("fThings") then .fThings |= map(select(any($matchPrefixes[]; startswith(input)))) else . end) | (if has("sThings") then .sThings |= map(select(any($matchPrefixes[]; startswith(input)))) else . end) )
代码解释
- 预处理匹配前缀:
将toDo数组中的每个元素按##分割,取前半部分存入$matchPrefixes变量,作为后续匹配的基准,避免直接对长字符串做部分匹配的冗余计算。 - 处理places数组:
- 遍历每个place对象,用
has("fThings")/has("sThings")判断字段是否存在,避免索引不存在的字段报错 - 对存在的*Things数组,用
map(select(any(...)))过滤出能被$matchPrefixes中任意前缀匹配的元素 - 保持其他字段和原结构完全不变
- 遍历每个place对象,用
测试结果
用给定JSON执行后,示例匹配结果:
- wapc1的fThings保留
pcs_app#2.1#bp、pcs_app#2.1#cc,移除其余不匹配项 - wapc3的fThings保留
pcs_app#2.1#d2c、pcs_app#2.1#ci、pcs_app#2.1#co、pcs_app#2.1#dq - wwc1的sThings保留
config_svc#1、erec_svc#1.27 - wwc4的sThings保留
bp_svc#1.46、config_svc#1、erec_svc#1.27
无匹配项的*Things数组会被过滤为空,原JSON结构完全保留
内容的提问来源于stack exchange,提问作者Jim Hastings
相关产品推荐
相关产品推荐

