jq: объекты со значениями массива не объединяются должным образом

У меня возникли проблемы с использованием jq для объединения нескольких объектов. В этом случае MY_OBJECTS — это поток объектов json с одним ключом каждый. Я объединяю их в один массив следующим образом:

$ echo ${MY_OBJECTS} | jq -s '.'
[
  {
    "Name1": [
      {
        "Item1": "Val1",
        "Item2": "Val2"
      }
    ]
  },
  {
    "Name1": [
      {
        "Item1": "Val3",
        "Item2": "Val4"
      }
    ]
  },
  {
    "Name2": [
      {
        "Item1": "Val5",
        "Item2": "Val6"
      }
    ]
  },
  {
    "Name2": [
      {
        "Item1": "Val7",
        "Item2": "Val8"
      }
    ]
  }
]

Я хотел бы объединить их в один объект, чтобы все объекты Item под одним именем были объединены в один массив. По сути, я хотел бы получить следующий вывод:

$ echo ${MY_OBJECTS} | jq -s <SOME_COMMAND>
{
  "Name1": [
    {
      "Item1": "Val1",
      "Item2": "Val2"
    },
    {
      "Item1": "Val3",
      "Item2": "Val4"
    }
  ],
  "Name2": [
    {
      "Item1": "Val5",
      "Item2": "Val6"
    },
    {
      "Item1": "Val7",
      "Item2": "Val8"
    }
  ]
}

Я ожидал, что echo ${MY_OBJECT} | jq -s add сделает это, но это перезаписало каждый объект следующим вместо добавления массивов, чтобы они были все в одном массиве (как если бы объекты добавлялись вместо массивов). Другими словами, записи выглядели так:

"Name1": [
  {
    "Item1": "Val3",
    "Item2": "Val4"
  }
]

Пока я хотел, чтобы они выглядели так:

"Name1": [
  {
    "Item1": "Val1",
    "Item2": "Val2"
  },
  {
    "Item1": "Val3",
    "Item2": "Val4"
  }
]

Любой совет будет принят во внимание!


person Lsquared13    schedule 17.03.2016    source источник


Ответы (3)


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

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

map(to_entries | add)
    | group_by(.key)
    | map({ (.[0].key): map(.value) | add })
person Jeff Mercado    schedule 17.03.2016

Реализация group_by/1 требует сортировки, поэтому здесь представлен альтернативный подход, использующий универсальный полезный фильтр addvalues, не требующий никакой сортировки. Обратите внимание, что единственным требованием к объектам во входном массиве является то, что значения каждого ключа должны быть совместимы по отношению к add.

# Given an array of objects, combine keys using add/0.
# This implementation does not depend on sorting.
def addvalues:
  reduce .[] as $o
    ( {}; reduce ($o|keys[]) as $key
      ( .; . + {($key): (.[$key] + $o[$key])} ));


addvalues
person peak    schedule 18.03.2016

Вот версия, похожая на решение peak addvalues, с отступом и небольшими комментариями для ясности. Он использует += для объединения массивов

reduce .[] as $i (                 #     $i: {"Name1":[{"Item1":"Val1","Item2":"Val2"}]}
     {}                            #
   ; reduce ($i|keys[]) as $k (    #     $k: "Name1"
          .                        #
        ; .[$k] += $i[$k]          # $i[$k]: [{"Item1":"Val1","Item2":"Val2"}]
     )
)
person jq170727    schedule 05.08.2017