根据与指定值完全匹配的任何元素选择数组

时间:2018-08-10 09:53:16

标签: json jq

有人知道如何实现吗?

我有一个带有嵌套数组的数组,例如tagNames,我想选择tagNames完全包含“自动测试”而不是“自动测试2”的所有项目。

{
  "servers":[
      {"id":1, "tagNames": ["auto-test",  "xxx"]},
      {"id":2, "tagNames": ["auto-test2", "xxxx"]}
  ]
}

到目前为止,我正在使用

echo '{"servers":[{"id":1,"tagNames":["auto-test","xxx"]},{"id":2,"tagNames":["auto-test2","xxxx"]}]}' |\
jq  '[ .servers[] | select(.tagNames | contains(["auto-test"])) ]'

我有两张唱片,但我只想要第一张。

[
  {
    "id": 1,
    "tagNames": [
      "auto-test",
      "xxx"
    ]
  },
  {
    "id": 2,
    "tagNames": [
      "auto-test2",
      "xxxx"
    ]
  }
]

所以我想要这个:

[
  {
    "id": 1,
    "tagNames": [
      "auto-test",
      "xxx"
    ]
  }
]

有什么主意吗?

3 个答案:

答案 0 :(得分:2)

您不应该使用contains/1,因为它不能像您期望的那样工作,特别是在处理字符串时。它将递归检查是否包含所有部件。因此,它不仅会检查字符串是否包含在数组中,而且还会检查字符串是否也是子字符串。

您需要写出条件,并根据条件检查所有标签。

[.servers[] | select(any(.tagNames[]; . == "auto-test") and all(.tagNames[]; . != "auto-test2"))]

答案 1 :(得分:1)

一种方法是使用index/1,例如

.servers[]
| select( .tagNames | index("auto-test"))

这将产生:

{"id":1,"tagNames":["auto-test","xxx"]}

如果要将其包装在数组中,则可以(例如)将上面的过滤器包装在方括号中。

答案 2 :(得分:0)

另一种解决方案是使用以下成语:first(select(_)):

jq '.servers[] | first(select(.tagNames[]=="auto-test"))' file

如果省略first,则servers数组中的同一项目可能会发射多次。