Разъединяя объект в jq, как я могу избежать повторного создания меток на каждом этапе конвейера? - PullRequest
0 голосов
/ 16 января 2019

Резюме:

Я успешно разработал способ удаления объектов в jq; однако рабочий код, который я написал, требует много повторений. Я чувствую, что, вероятно, есть более чистый или менее многословный способ достижения того же самого результата, и я хотел бы знать, что это такое.

Пример:

Используя следующую вложенную структуру компаний, предположим, что цель состоит в том, чтобы извлечь имя, ID, компанию и сайт для каждого человека в списке. (Мы можем игнорировать адрес.)

Введите:

{
  "company": "Initrode",
  "sites": [
    {
      "name": "HQ",
      "address": "123 Main Street",
      "personnel": [
        {
          "name": "John Smith",
          "UID": 12345
        },
        {
          "name": "Jane Doe",
          "UID": 23456
        }
      ]
    },
    {
      "name": "Branch Office",
      "address": "Spodunk, Nowhereville",
      "personnel": [
        {
          "name": "Fred Anderson",
          "UID": 56789
        },
        {
          "name": "Bill Jones",
          "UID": 34567
        }
      ]
    }
  ]
}
{
  "company": "Inittech",
  "sites": [
    {
      "name": "Main Office",
      "address": "5678 Avenue Blvd",
      "personnel": [
        {
          "name": "Fred Johnson",
          "UID": 6543
        },
        {
          "name": "James Fredson",
          "UID": 9876
        }
      ]
    },
    {
      "name": "Testing Station",
      "address": "Alaskan Wilderness",
      "personnel": [
        {
          "name": "Sally May",
          "UID": 5432
        },
        {
          "name": "Jack James",
          "UID": 8765
        }
      ]
    }
  ]
}

Рабочий код:

jq '{company,site: .sites[]}|
{company,site: .site.name,personnel: .site.personnel[]}|
{name: .personnel.name,id: .personnel.UID,company,site}' sample.json

Правильный вывод:

{
  "name": "John Smith",
  "id": 12345,
  "company": "Initrode",
  "site": "HQ"
}
{
  "name": "Jane Doe",
  "id": 23456,
  "company": "Initrode",
  "site": "HQ"
}
{
  "name": "Fred Anderson",
  "id": 56789,
  "company": "Initrode",
  "site": "Branch Office"
}
{
  "name": "Bill Jones",
  "id": 34567,
  "company": "Initrode",
  "site": "Branch Office"
}
{
  "name": "Fred Johnson",
  "id": 6543,
  "company": "Inittech",
  "site": "Main Office"
}
{
  "name": "James Fredson",
  "id": 9876,
  "company": "Inittech",
  "site": "Main Office"
}
{
  "name": "Sally May",
  "id": 5432,
  "company": "Inittech",
  "site": "Testing Station"
}
{
  "name": "Jack James",
  "id": 8765,
  "company": "Inittech",
  "site": "Testing Station"
}

Проблема:

Здесь много повторений. Помимо повторения внешних меток на каждой стадии конвейера, есть также повторение .site и .personnel во второй и третьей частях конвейера соответственно.

Мои реальные данные намного сложнее, поэтому это повторение еще хуже и его намного сложнее читать.

Кстати, вот неработающий код, который я пробовал ранее для той же цели выше:

jq '{company,site: .sites[].name,name: .sites[].personnel[].name,id: .sites[].personnel[].UID}' sample.json

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

Я не совсем знаю, как описать словами, что здесь нужно, но, надеюсь, приведенный выше пример поможет прояснить ситуацию.

Одним из способов описать это является то, что я пытаюсь объединить несколько пар имя-значение из массивов подобъектов в объект верхнего уровня, не возвращая вместе какие-либо комбинации пар имя-значение, взятые из различных подобъектов в одном и том же значении массива. Но это не совсем легко, даже для меня; отсюда приведенный выше пример ввода / вывода.


Просто для интереса, вот реальный рабочий код, который у меня есть, с обфусцированными именами атрибутов:

jq '.pears[]|{pear: .name,file: .somepath,toBeFiltered: (.appletypes[]|select(.name == "orange")|.bananas[]|{banana: .name,apples: .apples[]})}|{pear,file,banana: .toBeFiltered.banana,applestem: .toBeFiltered.apples.applestem,orangecomment: (.toBeFiltered.apples.peaches[]|select(.akey == "string")|.avalue.value),linenumber: (.toBeFiltered.apples.peaches[]|select(.akey == "string")|.line)}' realfile.json

1 Ответ

0 голосов
/ 16 января 2019

Возможно, вам не хватает утилиты jq переменных:

.company as $company
| .sites[]
| .name as $site
| .personnel[]
| { name, id: .UID, company: $company, site: $site }

Однако также возможно избежать переменных, используя скобки с осторожностью. Если вы не против, чтобы ключи были в несколько ином порядке, вы можете написать:

(.sites[] | ( (.personnel[] | { name, id: .UID} ) +  {site: .name} )) + {company} 

Если ключи должны быть в порядке, указанном в Q, вы можете просто добавить следующий фильтр к вышеуказанному конвейеру:

{name, id, company, site}
...