使用JQ从JSON中选择特定的,任意嵌套的对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用JQ从JSON中选择特定的,任意嵌套的对象相关的知识,希望对你有一定的参考价值。

我正在寻找有效的方法来搜索大型JSON对象以寻找与过滤器匹配的“子对象”(通过select(),我想)。但是,顶级JSON是包含任意嵌套的对象,包括更简单的值,对象和对象数组。例如:

{
  "name": "foo",
  "class": "system",
  "description": "top-level-thing",
  "configuration": {
    "status": "normal",
    "uuid": "id"
  },
  "children": [
    {
      "id": "c1",
      "class": "c1",
      "children": [
        {
          "id": "c1.1",
          "class": "c1.1"
        },
        {
          "id": "c1.1",
          "class": "FINDME"
        }
      ]
    },
    {
      "id": "c2",
      "class": "FINDME"
    }
  ],
  "thing": {
    "id": "c3",
    "class": "FINDME"
  }
}    

我有一个解决方案,它可以完成我想要的部分(并且可以理解):

jq -r '.. | arrays | .[] | select(.class=="FINDME"?) | .id'

返回:

c2
c1.1

...但是,它错过了c3,加上它改变了项目输出的顺序。此外,我希望这可以在可能非常大的JSON结构上运行,我想确保找到一个有效的解决方案。 jq新手(包括我自己)仍然可读的东西的奖励积分。

FWIW,我用它来帮助我的参考,以防他们帮助他人:

答案

这是一个流解析器解决方案。要理解它,你需要阅读--stream选项,但关键是输出包括以下形式的行:[PATH,VALUE]

program.jq

foreach inputs as $in (null;
  if has("id") and has("class") then null
  else . as $x
  | $in
  | if length != 2 then null
    elif .[0][-1] == "id" then ($x + {id: .[-1]})
    elif .[0][-1] == "class"
         and .[-1] == "FINDME" then  ($x + {class: .[-1]})
    else $x
    end
  end;
  select(has("id") and has("class")) | .id )

Invocation

jq -n --stream -f program.jq input.json

Output with sample input

"c1.1"
"c2"
"c3"
另一答案

对于小到中等大小的JSON输入,你在..的正确轨道上,但似乎你想选择objects,如下所示:

.. | objects | select(.class=="FINDME"?) | .id

对于非常大的JSON文档,这可能需要太多内存,因此可能需要了解jq的流解析器。不幸的是,它使用起来要困难得多,所以我建议尝试以上内容,如果你有兴趣,可以查看有关--stream选项的文档。

以上是关于使用JQ从JSON中选择特定的,任意嵌套的对象的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 jq 将任意简单 JSON 转换为 CSV?

使用 jq 为 JSON 对象的嵌套数组中的属性展平数组

使用 JQ 展平嵌套的 Json 对象

没有无限过滤链的JQ对象选择

使用 jq 展平嵌套的 JSON

如何按名称过滤键,然后使用 jq 访问嵌套对象