Размотать вложенный объект JSON с возможными нулевыми значениями с помощью jq?

#json #jq

#json #jq

Вопрос:

У меня есть ответ json с 3 элементами, который выглядит следующим образом:

 {
    "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
}
 

Обратите внимание, что в третьем элементе с id 46 domain.name отсутствуют последние две записи, 91 и 92 extra массива, поэтому они заменяются на null.

Это то, что я пробовал

 {"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}
 

но это не дает мне желаемого результата, оно возвращает декартово произведение всех возможных комбинаций в каждом элементе ответа!

Ответ №1:

Игнорируя на данный момент, что ожидаемый результат, как показано, не является, строго говоря, допустимым 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} ) ]
 

Это создает массив с нужными объектами. Если вы хотите создать недопустимый JSON, как показано в Q, не стесняйтесь использовать любое хитрое устройство, которое приходит вам в голову, например, убрать начальные и конечные квадратные скобки.

Примечания

  1. {"id": .id} может быть сокращено, как показано.
  2. Обратите внимание, как можно избежать комбинаторного взрыва, указав детализацию только один раз.
  3. Постфикс «?» в выражении E? имеет эффект try E catch empty
  4. Для обработки empty случая // был использован.
  5. Если вы хотите получить поток допустимых объектов JSON в качестве выходных данных, вы могли бы немного упростить ситуацию, отбросив -n опцию и используя inputs , чтобы обернуть все в массив.

Комментарии:

1. так это неправильный json, потому что в нем отсутствуют самые внешние фигурные скобки?

2. Отсутствуют самые внешние квадратные скобки.