jq如何按列表中的字段值过滤

时间:2021-05-31 12:58:17

标签: arrays json select filter jq

有这样的输入:

[
    {
        "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): 无法检查数组是否有字符串键

这甚至可能吗?

2 个答案:

答案 0 :(得分:2)

嗯,我设法做到了:

<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".versionrecycler.VersionRecycler"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/versions_rv" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" tools:listitem="@layout/row_versions_rv"/> </androidx.constraintlayout.widget.ConstraintLayout>

https://jqplay.org/s/g7AyRgARdU

根据这个答案: https://stackoverflow.com/a/46470951/2244766 在 1.5 以上的版本中,有一个新的 .[] | select(.foo as $tmpvar | ["aaa", "bbb"] | index ($tmpvar ) ) 运算符,使生活更轻松:

IN

答案 1 :(得分:0)

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