Сжатие документа JSON с использованием jq

Я рассматриваю следующий массив объектов JSON:

[
  {
    "index": "index1",
    "type": "type1",
    "id": "id1",
    "fields": {
      "deviceOs": [
        "Android"
      ],
      "deviceID": [
        "deviceID1"
      ],
      "type": [
        "type"
      ],
      "country": [
        "DE"
      ]
    }
  },
  {
    "index": "index2",
    "type": "type2",
    "id": "id2",
    "fields": {
      "deviceOs": [
        "Android"
      ],
      "deviceID": [
        "deviceID2"
      ],
      "type": [
        "type"
      ],
      "country": [
        "US"
      ]
    }
  }
]

и я хотел бы сгладить его, чтобы получить:

[
  {
    "index": "index1",
    "type": "type",
    "id": "id1",
    "deviceOs": "Android",
    "deviceID": "deviceID1",
    "country": "DE"
  },
  {
    "index": "index2",
    "type": "type",
    "id": "id2",
    "deviceOs": "Android",
    "deviceID": "deviceID2",
    "country": "US"
  }
]

Я пытаюсь работать с jq, но я не сглаживаю "fields". Как я должен это делать? На данный момент меня интересуют инструменты командной строки, но я также открыт для других предложений.

Ответ 1

Это было сложно сделать.

map
(
    with_entries(select(.key != "fields"))
    +
    (.fields | with_entries(.value = .value[0]))
)

Позвольте сломать его и объяснить его бит

  • Для каждого элемента массива...

    map(...)
    
  • Создайте новый объект, содержащий значения для всех, кроме свойства fields.

    with_entries(select(.key != "fields"))
    
  • Объедините это с...

    +
    
  • Каждый из fields проецирует каждое из значений на первый элемент каждого массива

    (.fields | with_entries(.value = .value[0]))
    

Ответ 2

Вы можете использовать этот фильтр:

[.[] | {index: .index, type: .type, id: .id, deviceOs: .fields.deviceOs[],deviceID: .fields.deviceID[],country: .fields.country[]}]

Вы можете проверить здесь https://jqplay.org

Ответ 3

Вот несколько вариантов, которые начинаются с объединения полей в содержащий объект с + и затем сглаживания элементов массива. Сначала мы заботимся о .fields с

  .[]
| . + .fields
| del(.fields)

который оставляет нас с объектами, которые выглядят как

{
  "index": "index1",
  "type": [
    "type"
  ],
  "id": "id1",
  "deviceOs": [
    "Android"
  ],
  "deviceID": [
    "deviceID1"
  ],
  "country": [
    "DE"
  ]
}

тогда мы можем сгладить ключи несколькими способами. Один из способов - использовать with_entries

| with_entries( .value = if .value|type == "array" then .value[0] else .value end )

другой способ - использовать уменьшить и setpath

| . as $v
| reduce keys[] as $k (
    {};
    setpath([$k]; if $v[$k]|type != "array" then $v[$k] else $v[$k][0] end)
  )