Объединить два сложных объекта JSON с массивами - PullRequest
0 голосов
/ 22 января 2019

У меня есть два следующих json в качестве ввода:

{
  "one": {
    "vars": [
      {
        "name": "a",
        "value": "a"
      },
      {
        "name": "b",
        "value": "b"
      }
    ]
  },
  "two": {
    "vars": [
      {
        "name": "c",
        "value": "c"
      },
      {
        "name": "d",
        "value": "d"
      }
    ]
  },
  "extras": "whatever"
}
{
  "one": {
    "vars": [
      {
        "name": "e",
        "value": "e"
      },
      {
        "name": "f",
        "value": "f"
      }
    ]
  },
  "two": {
    "vars": [
      {
        "name": "g",
        "value": "g"
      },
      {
        "name": "h",
        "value": "h"
      }
    ]
  }
}

И я хотел бы объединить их, чтобы получить следующий результат, где каждый массив vars каждого раздела объединен вместе:

{
  "one": {
    "vars": [
      {
        "name": "a",
        "value": "a"
      },
      {
        "name": "b",
        "value": "b"
      },
      {
        "name": "e",
        "value": "e"
      },
      {
        "name": "f",
        "value": "f"
      }
    ]
  },
  "two": {
    "vars": [
      {
        "name": "c",
        "value": "c"
      },
      {
        "name": "d",
        "value": "d"
      },
      {
        "name": "g",
        "value": "g"
      },
      {
        "name": "h",
        "value": "h"
      }
    ]
  },
  "extras": "whatever"
}

В идеале, но не обязательно:

  • ключи (здесь one и two) будут произвольными, и может присутствовать неопределенное количество из них.
  • массив vars не будет содержать дубликатов (на основе name), и будет применяться правый приоритет для переопределения значений из первого массива.

Мне удалось объединить два объекта и только 1 массив с помощью следующей команды, но ключ жестко закодирован, и я немного застрял оттуда:

jq -s '.[0].one.vars=([.[].one.vars]|flatten)|.[0]' file1.json file2.json

Ответы [ 2 ]

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

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

$A
| reduce keys_unsorted[] as $k (.;
    if .[$k] | (type == "object") and has("vars")
    then (.[$k]|.vars) += ($B[$k]|.vars) else . end )

Здесь, конечно, $ A и $ B относятся к двум объектам. Вы можете установить $ A и $ B несколькими способами.

Если вы хотите изменить порядок клавиш верхнего уровня, вы можете просто расширить вышеперечисленное с помощью фильтра, определяющего порядок, например: {extras, two, one}.

Чтобы избежать дублирования, я бы предложил написать вспомогательную функцию, чтобы сделать это, как показано в следующем разделе.

Как избежать дубликатов

def extend(stream):
  reduce stream as $s (.;
    (map(.name) | index($s|.name)) as $i
    | if $i then .[$i] += $s
      else . + [$s]
      end) ;


$A
| reduce keys_unsorted[] as $k (.;
    if .[$k] | (type == "object") and has("vars")
    then (.[$k].vars) = ( .[$k].vars | extend(($B[$k].vars[])))
    else . end
  )
0 голосов
/ 22 января 2019
jq -n 'input as $b | input
| .one.vars |= . + $b.one.vars
| .two.vars |= . + $b.two.vars' file2.json file1.json

file1.json должно идти после file2.json, чтобы сохранить extras.

...