如何使用jq按元素属性值过滤对象数组?

96

我喜欢使用jq过滤JSON文件:

jq . some.json

给定包含对象数组的 json:

{
  "theList": [
    {
      "id": 1,
      "name": "Horst"
    },
    {
      "id": 2,
      "name": "Fritz"
    },
    {
      "id": 3,
      "name": "Walter"
    },
    {
      "id": 4,
      "name": "Gerhart"
    },
    {
      "id": 5,
      "name": "Harmut"
    }
  ]
}

我想筛选列表,只显示id值为2和4的元素,所以预期输出为:

{
  "id": 2,
  "name": "Fritz"
},
{
  "id": 4,
  "name": "Gerhart"
}

我如何使用jq过滤json?我已经尝试了select和map,但是都没有成功,例如:
$ jq '.theList[] | select(.id == 2) or select(.id == 4)' array.json
true

16
请大家注意:这个问题是关于 jq 而不是 jQuery。 - T.J. Crowder
@T.J.Crowder 您太有趣了^^ 我在问题中澄清了:D - k0pernikus
4个回答

145

来自文档:

需要翻译的内容
jq '.[] | select(.id == "second")' 

输入 [{"id": "first", "val": 1}, {"id": "second", "val": 2}]

输出 {"id": "second", "val": 2}

我认为你可以这样做:

jq '.theList[] | select(.id == 2 or .id == 4)' array.json

jq '.theList[] | select(.id == 2) or select(.id == 4)' array.json 执行结果为:true o.O - k0pernikus
2
它将返回两个条件的评估结果,请尝试此操作: jq '.theList[] | select(.id == 2 or .id == 4)' - André Senra
jq '.theList[] | select(.id == 2 or .id == 4)' array.json 完成了任务,您可以更新您的答案 :) - k0pernikus

22
你可以在map中使用select
.theList | map(select(.id == (2, 4)))

或者更紧凑:

[ .theList[] | select(.id == (2, 4)) ]

虽然这种写法有点低效,因为每个被比较的值都要复制一次表达式。采用以下写法将更加高效并且可能更易读:

尽管以这种方式编写有些低效,因为表达式为每个被比较的值重复了一遍。采用以下写法将更高效,并且可能更易于阅读:

[ .theList[] | select(any(2, 4; . == .id)) ]

巧妙地使用 if 行为当条件返回多个结果 - jq170727

8

在此使用 select(.id == (2, 4)) 通常效率较低(请参见下文)。

如果你的 jq 工具有 IN/1,那么它可以用来实现更高效的解决方案:

.theList[] | select( .id | IN(2,3))

如果你的 jq 没有 IN/1,那么你可以按以下方式定义它:
def IN(s): first(select(s == .)) // false;

效率

发现低效的一种方法是使用debug。例如,下面的表达式会导致10次对debug的调用,而实际上只需要进行9次等式检查:

.theList[] | select( (.id == (2,3)) | debug )

["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",true]
{
  "id": 2,
  "name": "Fritz"
}
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",true]
{
  "id": 3,
  "name": "Walter"
}
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",false]
["DEBUG:",false]

index/1

原则上,使用index/1应该是高效的,但截至本文撰写时(2017年10月),它的实现虽然快速(它是用C语言编写的),但效率不高。


0

这里是一个使用indices的解决方案:

.theList | [ .[map(.id)|indices(2,4)[]] ]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接