jq 过滤内部数组元素但返回整个 JSON

Posted

技术标签:

【中文标题】jq 过滤内部数组元素但返回整个 JSON【英文标题】:jq to filter inner array elements but return the whole JSON 【发布时间】:2020-07-10 18:02:47 【问题描述】:

TL;DR

过滤***键的内部数组元素后如何返回整个 JSON?

详细解释

我有一个描述 COCO 图像数据库的 JSON,它的格式如下(不相关的元素被截断为 ...)。


  "info": 
    "description": "COCO 2017 Dataset",
    ...
  ,
  "licenses": [
    
      "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/",
      ...
    ,
    ...
  ],
  "images": [
    
      "license": 4,
      ...
    ,
  "annotations": [
    
      "segmentation": [
        [
          510.66,
          ...
        ]
      ],
      "area": 702.1057499999998,
      "iscrowd": 0,
      "image_id": 289343,
      "bbox": [
        473.07,
        395.93,
        38.65,
        28.67
      ],
      "category_id": 18,
      "id": 1768
    ,
  "categories": [
    
      "supercategory": "person",
      ...
    ,
  ]

我需要过滤annotations,其中category_id 具有多个值之一,例如1, 2

我可以成功过滤这样的category_ids

jq -C ' .annotations[] | select( .category_id == 1 or .category_id == 2 ) ' instances_val2017.json | less -R

但是,返回的只是整个 JSON 的 annotations 元素,如下所示。


  "segmentation": [
    [
      162.72,
      ...
    ]
  ],
  "area": 426.9120499999995,
  "iscrowd": 0,
  "image_id": 45596,
  "bbox": [
    161.52,
    507.18,
    46.45,
    19.16
  ],
  "category_id": 2,
  "id": 124742


...

我知道可以通过将表达式包装在 [] 中来将这些元素作为数组返回,但是如何在过滤指定的类别 ID 后返回整个原始 JSON?

【问题讨论】:

【参考方案1】:

好吧,我昨天花了 3 个小时试图解决这个问题,然后今天早上我发布了这个问题,随后想通了!

这里是使用|= 操作符的解决方案,它可以修改元素。

jq '.annotations |= map(select(.category_id | contains(1,2)))' instances_val2017.json

根据@peak 的建议,这里是用== 代替contains 的命令。

jq '.annotations |= map(select(.category_id == (1,2)))' instances_val2017.json

【讨论】:

contains 语义非常复杂,很容易产生“意外结果”。它也可能很慢。在这种特殊情况下,您可以简单地写map(select(.category_id == (1,2)))。一般来说,index(小写)和IN(大写)也值得考虑。

以上是关于jq 过滤内部数组元素但返回整个 JSON的主要内容,如果未能解决你的问题,请参考以下文章

在 Lumen 7 中验证时如何返回自定义 JSON 数组名称和内部元素?

jq 的grep(); 数组筛选方法

如何使用jq根据内部数组中的值过滤对象数组?

通过按键过滤数组,使用 jq 展平 JSON 文档

jq获取元素的宽高(内边距和外边距)

jq-outerhtml不能执行新元素内部的js解决方案