【问题标题】:jq how to filter by field value in listjq如何按列表中的字段值过滤
【发布时间】:2021-08-18 18:56:16
【问题描述】:

有这样的输入:

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

我想选择“foo”键等于“aaa”或“bbb”的所有对象。所以解决方案很明显:

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

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

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

导致错误:

jq: 错误:语法错误,意外 IDENT,期待 ';'或 ')' (Unix shell 引用问题?),第 1 行:

我也试过这个:

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

但也不是很好......

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

这可能吗?

【问题讨论】:

  • 这里相关的jq过滤器是IN,而不是in
  • AFAIK,IN 运算符是自 jq 1.6.somethig
  • 即使你的 jq 没有 IN,你仍然可以通过先添加它的 def 来使用它,这很容易找到,例如通过谷歌搜索。
  • 好吧 - 当然。但我可以像接受的答案一样简单地做;)

标签: arrays json select filter jq


【解决方案1】:

嗯,我设法做到了:

.[] | 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"))

【讨论】:

    【解决方案2】:

    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 中的其他数据生成正则表达式,您也可以这样做:

    . 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(一次获取正则表达式值,一次使用它)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-23
      • 2020-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-15
      相关资源
      最近更新 更多