Как объединить и добавить два файла JSON с помощью общего ключа без потери других данных - PullRequest
2 голосов
/ 23 апреля 2019

У меня есть два файла json, в которых есть несколько объектов json.Я хочу объединить два файла json в linux, используя jq с group_by (.id). На самом деле мне не нужно использовать jq, но мне нужно создавать файлы сценариев оболочки linux.

Конечно, я пытался найти много решенийно они не работали точно так, как я хочу.

Ввод 1: file1.json

{"id":"1234", "branch": "master", "arr":["say", "one", "more"]}
{"id":"102", "branch": "master", "arr":["yes"]}
{"id":"1228", "branch": "master"}

Ввод 2: file2.json

{"id":"1234", "branch": "dev", "other": "value", "arr":["what"]}
{"id":"102", "branch": "dev"}
{"id":"0806", "branch": "master"}

Что яожидаемое значение равно

{"id":"1234", "branch": ["master", "dev"], "other": "value", "arr":["say", "one", "more", "what"]}
{"id":"102", "branch": ["master", "dev"], "arr":["yes"]}
{"id":"1228", "branch": "master"}
{"id":"0806", "branch": "master"}

, но фактический результат равен

{"id":"1234", "branch": "dev", "other": "value", "arr":["what"]}
{"id":"102", "branch": "dev"}
{"id":"0806", "branch": "master"}

1 Ответ

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

Далее мы используем обобщенную функцию combine для объединения двух объектов, как определено ниже.

С помощью этой функции и использования вызова, такого как:

jq -n -f combine.jq --slurpfile f1 file1.json --slurpfile f2 file2.json

и предполагая, что ваш jq имеет INDEX/2, тогда решение можно получить, просто написав:

INDEX( $f1[]; .id) as $d1
| INDEX( $f2[]; .id) as $d2
| reduce (($d1+$d2)|keys_unsorted)[] as $id
    ({}; .[$id] = ($d1[$id] | combine($d2[$id])) )
| .[]

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

Если в вашей установке jq нет INDEX/2, то сейчас самое время обновить, но альтернативой было бы скопировать его def из builtin.jq.(см. «комментарий» ниже).

объединить / 1

Далее, который предназначен для jq 1.5 или более поздней, детали объединения значений оставлены для внутренней функции, aggregate.

# Combine . with obj using aggregate/2 for shared keys whose values differ
def combine($obj):

  # Combine two entities in an array-oriented fashion:
  # if both are arrays:  a + b 
  # else if a is an array: a + [b]
  # else if b is an array: [a] + b
  # else [a, b]
  def aggregate(a; b):
    if (a|type) == "array" then
      if (b|type) == "array" then a + b
      else a + [b]
      end
    else
      if (b|type) == "array" then [a] + b
      else [a, b]
      end
    end;

  if . == null then $obj
  elif $obj == null then .
  else reduce ($obj|keys_unsorted[]) as $key (.;
         if .[$key] == $obj[$key] then . 
         else .[$key] = if has($key) and ($obj|has($key))
                        then aggregate( .[$key]; $obj[$key] )
                        else .[$key] + $obj[$key]
                end
         end )
   end ;
...