JQ: Как создать JSON объект, используя данные, выбранные jq? - PullRequest
2 голосов
/ 23 апреля 2020

У меня есть сложный JSON файл, который содержит сотни «атрибутов» с их типами, идентифицированными как «objectTypeAttributeId».

Я знаю, что objectTypeAttributeId = 328 означает tickedid, objectTypeAttributeId = 329 содержит массив имен хостов et c ..

Существует упрощенная версия файла:

{
  "objectEntries": [
    {
      "attributes": [
        {
          "id": 279792,
          "objectTypeAttributeId": 328,
          "objectAttributeValues": [
            {
              "displayValue": "ITSM-24210"
            }
          ]
        },
        {
          "id": 279795,
          "objectTypeAttributeId": 329,
          "objectAttributeValues": [
            {
              "displayValue": "testhost1"
            },
            {
              "displayValue": "testhost2"
            }
          ]
        },
        {
          "id": 279793,
          "objectTypeAttributeId": 330,
          "objectAttributeValues": [
            {
              "displayValue": "28.02.2020 11:45"
            }
          ]
        }
      ]
    }
  ]
}

Мне нужно создать вывод JSON, используя определенные выбранные значения (согласно значению "objectTypeAttributeId") ввода JSON в таком формате:

{
    "tickets": [
        {
            "ticketid": "ITSM-24210",
            "hostnames": ["testhost1", "testhost2"],
            "date": "28.02.2020 11:45"
        }
    ]
}

Я новичок в jq, в XSLT это разрешимо с использованием шаблона stati c с заполнителями для выбранных значений.

I пробовал этот подход, есть мой фильтр jq:

.objectEntries[].attributes[] |
  {ticketid: select(.objectTypeAttributeId == 328) | .objectAttributeValues[0].displayValue},
  {hostnames: select(.objectTypeAttributeId == 329) | [.objectAttributeValues[].displayValue]},
  {date: select(.objectTypeAttributeId == 330) | .objectAttributeValues[0].displayValue}

, но результат этого подхода:

{
  "ticketid": "ITSM-24210"
}
{
  "hostnames": [
    "testhost1",
    "testhost2"
  ]
}
{
  "date": "28.02.2020 11:45"
}

И все мои последующие попытки лучше отформатировать вывод заканчиваются на ломаном jq фильтр или фильтр, который ничего не возвращает.

Пожалуйста, есть идеи, как решить эту проблему?

Ответы [ 2 ]

2 голосов
/ 23 апреля 2020

Предполагается, что для каждой записи объекта должен быть сгенерирован тикет:

{tickets: [
  .objectEntries[]
  | [.attributes[]
    | [.objectTypeAttributeId,
      (.objectAttributeValues | map(.displayValue))] as [$id, $val]
    |   if $id == 328 then {ticketId:  $val[0]}
      elif $id == 329 then {hostnames: $val}
      elif $id == 330 then {date:      $val[0]}
      else empty end
  ] | add
]}

Онлайн-демонстрация

0 голосов
/ 23 апреля 2020

Здесь мы go, это не красиво, может быть, есть лучшее решение, но оно работает: https://jqplay.org/s/sxussfa2Vj

.objectEntries | {tickets: map(.attributes | 
{ticketID: (reduce .[] as $r (null;  if $r.objectTypeAttributeId == 328 
then $r.objectAttributeValues[0].value else . end)),
date: (reduce .[] as $r (null;  if $r.objectTypeAttributeId == 330
then $r.objectAttributeValues[0].value else . end)), 
hostnames: (reduce .[] as $r ([];  if $r.objectTypeAttributeId == 329 
then $r.objectAttributeValues | map(.value) else . end))})}

Там происходит много распаковки и перепаковки вот что-то отвлекает от ядра. У вас есть массив билетов (или записи), и над ними мы отображаем. Различные свойства, которые мы должны получить из разных элементов массива, это делается с помощью метода Reduce. Reduce просматривает массив объектов, выбирает правильный и отслеживает значение.

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

Ваше оригинальное решение почти работает, вы хорошо поработали, просто нужна карта:

.objectEntries[].attributes | 
{ticketid: . | map(select(.objectTypeAttributeId == 328))[0] | 
.objectAttributeValues[0].displayValue, 
date: . | map(select(.objectTypeAttributeId == 330))[0] |
.objectAttributeValues[0].displayValue, 
hostnames: . | map(select(.objectTypeAttributeId == 329))[0] | 
[.objectAttributeValues[].displayValue]}

Попробуйте, она даже работает с несколькими билетами;) https://jqplay.org/s/ydoCgv9vsI

...