jq查询嵌套JSON数组 正确匹配关联字段避免笛卡尔积
问题场景
现有如下结构的嵌套JSON数组:
[ { "devices": [ { "files": [ { "id": "2", "type": "file" } ], "path": "/tmp/file1" }, { "files": [ { "id": "3", "type": "file" } ], "path": "/tmp/file2" } ], "name": "a" }, { "devices": [ { "files": [ { "id": "4", "type": "file" } ], "path": "/tmp/tfile" }, { "files": [ { "id": "5", "type": "file" } ], "path": "/var/mfile" } ], "name": "b" } ]
需要逐行输出三个一一对应的值:顶层name字段值、其下devices数组元素的path字段值、该device元素下files数组的id字段值,预期输出格式:
a /tmp/file1 2 a /tmp/file2 3 b /tmp/tfile 4 b /var/mfile 5
最初尝试的jq命令如下:
cat myfile.json | jq '.[] | "\(.name), \(.devices[].path) \(.devices[].files[].id)"'
执行后出现笛卡尔积问题,path与id错误交叉组合,实际错误输出:
"a, /tmp/file1 2" "a, /tmp/file2 2" "a, /tmp/file1 3" "a, /tmp/file2 3" "b, /tmp/tfile 4" "b, /var/mfile 4" "b, /tmp/tfile 5" "b, /var/mfile 5"
额外需求:支持先筛选name等于指定值(例如"a")的顶层元素,再遍历输出关联正确的字段值。
错误原因
原命令中两次独立调用.devices[]展开数组,两次迭代逻辑完全独立,jq会对两个独立迭代的结果做全量组合,最终输出笛卡尔积,无法保证path和id归属于同一个device元素。
正确写法
使用-r参数输出原始字符串(避免结果自动包裹JSON格式的双引号),通过变量绑定留存各层级上下文,逐层迭代保证字段归属关系匹配:
- 全量输出所有关联正确的条目:
jq -r ' .[] | .name as $topName | .devices[] | .path as $devPath | .files[] | "\($topName) \($devPath) \(.id)" ' myfile.json
- 筛选指定name(例如值为"a")的条目后输出:
jq -r ' .[] | select(.name == "a") | .name as $topName | .devices[] | .path as $devPath | .files[] | "\($topName) \($devPath) \(.id)" ' myfile.json
逻辑说明
- 严格按照层级顺序迭代:顶层数组元素→devices数组元素→files数组元素,每一步迭代都在当前父元素的上下文内执行,不会出现跨元素交叉匹配
- 用
as语法将当前层级需要的字段值绑定为变量,供内层迭代拼接使用 select(.name == "目标值")放在顶层元素遍历步骤之后,即可提前过滤不需要的顶层条目,不会破坏后续字段关联逻辑
内容的提问来源于stack exchange,提问作者Vadiraj
相关产品推荐
相关产品推荐

