首页 > 解决方案 > 使用 jq 进行嵌套过滤

问题描述

jq 的第一次用户,我想根据其中的值过滤掉对象,我正在努力弄清楚。

我有一个很大的 json 文件,里面有很多产品数据,如下所示。我想根据他们拥有的 website_id 过滤掉。

示例输入:

[{
    "product_id": "2",
    "sku": "PROD2",
    "name": "Product Name 2",
    "set": "4",
    "type": "simple",
    "category_ids": {
      "item": "15"
    },
    "website_ids": {
      "item": [
      "1",
      "4"
    ]}
},{
    "product_id": "3",
    "sku": "PROD3",
    "name": "Product Name 3",
    "set": "4",
    "type": "simple",
    "category_ids": {
      "item": "15"
    },
    "website_ids": {
      "item": [
      "1",
      "2"
    ]}
}]

期望的输出:

[{
    "product_id": "2",
    "sku": "PROD2",
    "name": "Product Name 2",
    "set": "4",
    "type": "simple",
    "category_ids": {
      "item": "15"
    },
    "website_ids": {
      "item": [
      "1",
      "4"
    ]}
}]

我已经尝试了一些不同的东西,但我显然只是没有得到它。

jq 'map(.website_ids.item[] | contains("4"))'

给我:

[
  false,
  true,
  false,
  false
]

这似乎与我想要的 website_ids 项目相匹配,但我不确定如何从中获取完整的 JSON 对象。

任何帮助将不胜感激!谢谢。

编辑:

我已经使用了它,它适用于我的示例:

map(select(.website_ids.item[] | contains("4")))

我意识到我的示例和我实际测试的文件有一些差异。

有时,产品的 website_id 项目有这个:

“website_ids”:{“项目”:“2”}

导致错误:

Cannot iterate over string ("2")

有没有解决的办法?

标签: jsonshellselectcommand-linejq

解决方案


您需要做的就是select在 map 函数中添加一个调用,如下所示:

jq 'map(select(.website_ids.item[] | contains("4")))'

编辑后,它有点复杂,但可以通过检查类型.website_ids.item然后根据该类型进行包含检查或简单的相等检查来解决它:

map((select((.website_ids.item | type) == "array") | select(.website_ids.item[] | contains("4"))), (select((.website_ids.item | type) == "string") | select (.website_ids.item == "4")))

在这里,它的格式更具可读性:

map(
    (select((.website_ids.item | type) == "array") | select(.website_ids.item[] | contains("4"))),
    (select((.website_ids.item | type) == "string") | select (.website_ids.item == "4"))
)

推荐阅读