如何在jq中正确使用select?数组遍历语法差异疑问
jq命令用法疑问解答
示例JSON
{ "project" : [ { "name" : "dungeon master", "date" : "2022-05-11T16:07:29.000Z", "status" : "active" }, { "name" : "great gatsby", "date" : "2023-04-20T19:49:26.000Z", "status" : "active" }, { "name" : "hundred years", "date" : "2022-11-29T23:37:29.000Z", "status" : "active" }, { "name" : "passage to india", "date" : "2022-11-22T04:16:50.000Z", "status" : "active" } ] }
分步写法(成功案例)
# 逐个检查name是否包含"ma" .project[] | .name | contains("ma") >> true >> false >> false >> false # 筛选出符合条件的project对象 .project[] | select( .name | contains("ma")) >> { >> "name": "dungeon master", >> "date": "2022-05-11T16:07:29.000Z", >> "status": "active" >> } # 提取符合条件的name字段 .project[] | select( .name | contains("ma")) | .name >> "dungeon master" # success
缩写写法(问题案例)
# 逐个检查name是否包含"ma",和分步写法效果一致 .project[].name | contains("ma") >> true >> false >> false >> false # 错误写法:返回整个JSON对象 select(.project[].name | contains("ma")) >> get back whole json # 错误写法:返回null select(.project[].name | contains("ma")) | .name >> null
问题解答
1. 为什么select(.project[].name |contains("ma"))|.name无法正常工作?错误理解是什么?
select()的作用是过滤当前输入的对象,执行select(.project[].name |contains("ma"))时,当前输入的是整个根JSON对象。.project[].name会遍历所有project的name字段,生成一组true/false结果,但select()的判断逻辑是:只要这组结果里至少有一个true,就会保留当前输入的根对象。
之后用| .name时,根JSON对象本身没有name字段,所以返回null。
核心错误是误以为select()内部的.project[].name会逐个过滤数组元素,但实际上select()是针对当前顶层输入对象(根对象)做判断,没有先把数组元素拆出来单独处理,完全搞错了过滤层级。
2. .array[].key与.array[] | .key的概念差异是什么?为何会导致写法失效?
单纯取值时,.array[].key和.array[] | .key效果一致:都会遍历数组每个元素,提取每个元素的key字段,生成对应结果序列。
但和select()结合时差异明显:
.array[] | .key是先把数组每个元素拆成独立对象,再对每个对象提取key;如果是.array[] | select(.key | ...),就是对每个独立数组元素做过滤,符合条件的元素会被保留。- 把
.project[].name放在select()内部时,是在根对象层面遍历所有project的name,生成的true/false序列只会用来判断是否保留根对象,不会逐个处理数组元素。这就导致select()直接返回整个根对象,后续取.name自然得到null。
内容的提问来源于stack exchange,提问作者sylye
相关产品推荐
相关产品推荐

