jq如何根据列表中的字段值进行筛选



具有如下输入:

[
{
"foo": "aaa",
"bar": 111
},
{
"foo": "bbb",
"bar": 111
},
{
"foo": "ccc",
"bar": 222
},
{
"foo": "aaa",
"bar": 333
},
{
"foo": "ddd",
"bar": 444
}
]

我想选择所有带有";foo";key等于";aaa";或";bbb";。因此解决方案是显而易见的:

.[] | select ( .foo=="aaa" or .foo=="bbb" )(https://jqplay.org/s/x7FGo1uQNW)

但我想增强它,并将x=y or x=z替换为sql风格的x in (y,z)。我被卡住了,作为自然的尝试:

.[] | select ( .foo in (["aaa", "bbb"]) )

导致错误:

jq:error:语法错误,意外的IDENT,应为";"或"("(Unix shell引用问题?(,第1行:

我也尝试过这个:

.[] | select ( .foo | in (["aaa", "bbb"]) )

但也不太好。。。

jq:error(at:21(:无法检查数组是否有字符串密钥

这可能吗?

嗯,我用这个做到了:

.[] | select(.foo as $tmpvar | ["aaa", "bbb"] | index ($tmpvar ) )

https://jqplay.org/s/g7AyRgARdU

根据这个答案:https://stackoverflow.com/a/46470951/2244766在1.5以上的版本中,有一个新的IN操作符,它让生活变得更轻松:

.[] | select(.foo|IN("aaa","bbb"))

SQL风格的运算符作为一种直接的选择机制对我来说效果不佳;我相信它们有一个非常具体的用例,它们非常适合这个用例,而对于其他任何东西,它们(充其量(都很笨重。至少这是我的经验。我也没有真正弄清楚具体的用例是什么。

以所有这些为背景,我的建议是使用一个简单的正则表达式测试:

map(select(.foo | test("aaa|bbb")))

给定示例JSON:

<~> $ jq . /tmp/so4229.json
[
{
"foo": "aaa",
"bar": 111
},
{
"foo": "bbb",
"bar": 111
},
{
"foo": "ccc",
"bar": 222
},
{
"foo": "aaa",
"bar": 333
},
{
"foo": "ddd",
"bar": 444
}
]

上述过滤器将导致:

<~> $ jq 'map(select(.foo | test("aaa|bbb")))' /tmp/so4229.json
[
{
"foo": "aaa",
"bar": 111
},
{
"foo": "bbb",
"bar": 111
},
{
"foo": "aaa",
"bar": 333
}
]

如果您需要基于JSON中的其他数据生成regex,也可以这样做:

. as $data | map(select(.bar==111) | .foo) | join("|") as $regex | . = $data | map(select(.foo | test($regex)))

这将导致:

<~> $ jq '. as $data | map(select(.bar==111) | .foo) | join("|") as $regex | . = $data | map(select(.foo | test($regex)))' /tmp/so4229.json
[
{
"foo": "aaa",
"bar": 111
},
{
"foo": "bbb",
"bar": 111
},
{
"foo": "aaa",
"bar": 333
}
]

可能有更好的方法可以运行JSON两次(一次获取regex值,一次使用(。

最新更新