首页 > 解决方案 > 使用 jq 展开具有可能空值的嵌套 JSON 对象?

问题描述

我有一个包含 3 个项目的 json 响应,如下所示:

{
    "id": 44,
    "extra": [{
        "domain": {
            "id": 3,
            "name": "person"
        },
        "entity": {
            "label": "Noon",
            "serial": 8938493
        }
    },
    {
        "domain": {
            "id": 4,
            "name": "place"
        },
        "entity": {
            "label": "Rad",
            "serial": 8932321
        }
    }]
}
{
    "id": 45,
    "extra": null
    
}
{
    "id": 46,
    "extra": [{
        "domain": {
            "id": 90,
            "name": "animal"
        },
        "entity": {
            "label": "Foo",
            "serial": 892121
        }
    },
    {
        "domain": {
            "id": 91
        },
        "entity": {
            "label": "Ear",
            "serial": 823414
        }
    },
    {
        "domain": {
            "id": 92
        },
        "entity": {
            "label": "Owl",
            "serial": 889232
        }
    }]
}

我的目标是将此响应转化为:

{
    "id": 44,
    "extra_domain_id": 3,
    "extra_domain_name": "person",
    "extra_entity_label": "Noon",
    "extra_entity_serial": 8938493
},
{
    "id": 44,
    "extra_domain_id": 4,
    "extra_domain_name": "place",
    "extra_entity_label": "Rad",
    "extra_entity_serial": 8932321
},
{
    "id": 45,
    "extra_domain_id": null,
    "extra_domain_name": null,
    "extra_entity_label": null,
    "extra_entity_serial": null
},
{
    "id": 46,
    "extra_domain_id": 90,
    "extra_domain_name": "animal",
    "extra_entity_label": "Foo",
    "extra_entity_serial": 892121
},
{
    "id": 46,
    "extra_domain_id": 91,
    "extra_domain_name": null,
    "extra_entity_label": "Ear",
    "extra_entity_serial": 823414
},
{
    "id": 46,
    "extra_domain_id": 92,
    "extra_domain_name": null,
    "extra_entity_label": "Owl",
    "extra_entity_serial": 889232
}

请注意,在数组的最后两个条目 91 和 92 中缺少id46的第三项,因此它们被替换为 null。 这是我尝试过的domain.nameextra

{"id": .id, "extra_domain_id": .extra[].domain.id, "extra_domain_name": .extra[].domain.name, "extra_entity_label": .extra[].entity.label, "extra_entity_serial": .extra[].entity.serial}

但它没有给我想要的输出,它返回响应中每个项目中所有可能组合的笛卡尔积!

标签: jsonjq

解决方案


暂时忽略所示的预期输出不是严格意义上的有效 JSON,一种可能的解决方案是使用如下调用:

jq -nf program.jq input.json

其中 program.jq 包含:


[inputs
 | {id} +
   ((.extra[]? // {})
    | {"extra_domain_id": .domain.id,
       "extra_domain_name": .domain.name,
       "extra_entity_label": .entity.label,
       "extra_entity_serial": .entity.serial} ) ]

这将生成一个包含所需对象的数组。如果您希望生成 Q 中所示的无效 JSON,请随意使用您遇到的任何不正当手段,例如去掉前导方括号和尾随方括号。

笔记

  1. {"id": .id}可以缩写,如图。
  2. 请注意如何通过仅指定一次项来避免组合爆炸。
  3. 后缀“?” 在表达式E?中具有以下效果try E catch empty
  4. 处理的empty情况下,//一直使用。
  5. 如果您想要一个有效的 JSON 对象流作为输出,您可以通过删除-n选项和使用inputs将所有内容包装到数组中来简化一些事情。

推荐阅读