【发布时间】:2014-09-03 17:05:20
【问题描述】:
我有一个这样的文件:
{"items":["blue","green"]}
{"items":["yellow","green"]}
{"items":["blue","pink"]}
如何使用jq 选择并仅显示“items”数组中包含“blue”的 JSON 值?
所以输出将是:
{"items":["blue","green"]}
{"items":["blue","pink"]}
【问题讨论】:
我有一个这样的文件:
{"items":["blue","green"]}
{"items":["yellow","green"]}
{"items":["blue","pink"]}
如何使用jq 选择并仅显示“items”数组中包含“blue”的 JSON 值?
所以输出将是:
{"items":["blue","green"]}
{"items":["blue","pink"]}
【问题讨论】:
找到答案
jq 'select(.items | index("blue"))'
【讨论】:
2017 年 1 月 30 日,添加了一个名为 IN 的内置函数,用于有效测试 JSON 实体是否包含在流中。它还可以用于有效地测试数组中的成员资格。在本例中,相关用法为:
select( .items as $items | "blue" | IN($items[]) )
如果你的 jq 没有IN/1,那么只要你的 jq 有first/1,你就可以使用这个等价的定义:
def IN(s): . as $in | first(if (s == $in) then true else empty end) // false;
在这里使用any/0 效率相对较低,例如与使用any/1相比:
select( any( .items[]; . == "blue" ))
(实际上,index/1 通常足够快,但目前(jq 1.5 和至少到 2017 年 7 月的版本)的实现并不理想。)
【讨论】:
虽然您所拥有的确实有效,但使用contains 会更正确。我会避免这种使用,因为它会导致混乱。 index("blue") 是 0,人们不会认为这是一个真实的值,可能会期望它被排除在结果之外。
考虑改用这个过滤器:
select(.items | contains(["blue"]))
如果您想要多个匹配项,只需向数组中添加更多内容,它就有额外的好处。
正如 Will 在 cmets 中指出的那样,这并不完全正确。此处使用子字符串匹配(contains 递归使用)比较字符串。
回想起来,contains 并没有像我想象的那样成功。使用index 有效,但我个人不会使用它。通过查找对我来说感觉不对的索引来确定一个项目是否在集合中。使用contains 对我来说更有意义,但鉴于这些信息,在这种情况下它并不理想。
这是一个应该可以正常工作的替代方法:
select([.items[] == "blue"] | any)
或者,如果您希望能够匹配更多值,则可以采用更具可扩展性的方式:
select(.items as $values | ["blue", "yellow"] | map([$values[] == .] | any) | all)
【讨论】:
jq -n '["foobar","bar","baz"] | [.[] | select( . == "foobar" )] | length > 0' 至少有 潜在并行运行搜索。
我需要对对象的相同情况使用“正则表达式”。 (当然,在另一种情况下)。我编写代码是因为我没有在这些页面中找到满足我需求的解决方案。这可能对某人有用。
例如,使用正则表达式匹配蓝色:
jq 'select(.items[]|test("bl.*"))' yourfile.json
【讨论】: