Как объединить файл JSON с помощью JQ? - PullRequest
0 голосов
/ 17 января 2019

Я использую инструменты jq (jq-json-процессор) в сценарии оболочки для анализа json.

У меня есть 2 файла json, и я хочу объединить их в один уникальный файл

Здесь содержимое файлов:

file1:

{"tag_id" : ["t1"], "inst_id" : "s1"}
{"tag_id" : ["t1"], "inst_id" : "s2"}

file2:

{"tag_id" : ["t2"], "inst_id" : "s1"}
{"tag_id" : ["t2"], "inst_id" : "s2"}
{"tag_id" : ["t2"], "inst_id" : "s3"}

ожидаемый результат:

{"tag_id" : ["t1","t2"], "inst_id" : "s1"}
{"tag_id" : ["t1","t2"], "inst_id" : "s2"}
{"tag_id" : ["t2"], "inst_id" : "s3"}

Ответы [ 3 ]

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

Вот такой подход, как соединение. Предполагается, что ваш jq имеет INDEX/2 и поддерживает параметр командной строки --slurpfile. Если ваш jq не имеет их, сейчас самое время обновить, хотя есть и простые обходные пути.

Воззвание

jq -n --slurpfile file1 file1.json -f join.jq file2.json

join.jq

def join(s2; joinField; field):
  INDEX(.[]; joinField) 
  | reduce s2 as $x (.;
      ($x|joinField) as $key
      | if .[$key] then (.[$key]|field) += ($x|field)
        else .[$key] = $x
      end )
  | .[]
  ;

$file1 | join(inputs; .inst_id; .tag_id)
0 голосов
/ 18 января 2019

В этом очень эффективен следующий подход:

(a) используется тот факт, что file1.json и file2.json являются потоками объектов, что позволяет избежать использования памяти, необходимой для хранения этих объектов в виде массивов;

(b) избегает сортировки (как, например, по group_by)

Ключевой концепцией является добавление объектов по ключу. Для выполнения сложения по ключу объектов в потоке мы определяем следующую обобщенную функцию:

# s is assumed to be a stream of mutually
# compatible objects in the sense that, given
# any key of any object, the values at that key
# must be compatible w.r.t. `add`
def keywise_add(s):
  reduce s as $x ({};
     reduce ($x|keys_unsorted)[] as $k (.; 
       .[$k] += $x[$k]));

Теперь задачу можно выполнить следующим образом:

keywise_add(inputs | {(.inst_id): .tag_id} )
| keys_unsorted[] as $k
| {tag_id: .[$k], inst_id: $k}

Воззвание

С помощью вышеуказанной программы в add.jq вызов:

jq -c -n -f add.jq file1.json file2.json

дает:

{"tag_id":["t1","t2"],"inst_id":"s1"}
{"tag_id":["t1","t2"],"inst_id":"s2"}
{"tag_id":["t2"],"inst_id":"s3"}

Протест

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

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

Одним из способов является использование group_by:

jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json -f merge.jq

где merge.jq содержит:

def sigma(f): reduce f as $x (null; . + $x);

$file1 + $file2
| group_by(.inst_id)[]
| {tag_id: sigma(.[].tag_id), inst_id: .[0].inst_id }
...