Как объединить 2 объекта JSON из 2 файлов с помощью jq?


124

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

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

Вот содержимое файлов:

file1

{
    "value1": 200,
    "timestamp": 1382461861,
    "value": {
        "aaa": {
            "value1": "v1",
            "value2": "v2"
        },
        "bbb": {
            "value1": "v1",
            "value2": "v2"
        },
        "ccc": {
            "value1": "v1",
            "value2": "v2"
        }
    }
}

file2

{
    "status": 200,
    "timestamp": 1382461861,
    "value": {
        "aaa": {
            "value3": "v3",
            "value4": 4
        },
        "bbb": {
            "value3": "v3"
        },      
        "ddd": {
            "value3": "v3",
            "value4": 4
        }
    }
}

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

{
    "value": {
        "aaa": {
            "value1": "v1",
            "value2": "v2",
            "value3": "v3",
            "value4": 4
        },
        "bbb": {
            "value1": "v1",
            "value2": "v2",
            "value3": "v3"
        },
        "ccc": {
            "value1": "v1",
            "value2": "v2"
        },
        "ddd": {
            "value3": "v3",
            "value4": 4
        }
    }
}

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

{
  "ccc": {
    "value2": "v2",
    "value1": "v1"
  },
  "bbb": {
    "value2": "v2",
    "value1": "v1"
  },
  "aaa": {
    "value2": "v2",
    "value1": "v1"
  }
}
{
  "ddd": {
    "value4": 4,
    "value3": "v3"
  },
  "bbb": {
    "value3": "v3"
  },
  "aaa": {
    "value4": 4,
    "value3": "v3"
  }
}

Используя эту команду:

jq -s '.[].value' file1 file2

1
Вы пробовали jsontool? github.com/trentm/json
Nano Taboada

Еще нет, посмотрю. Thx
Janfy

Для этого jsonиспользуйте:cat f1 f2 | json --deep-merge
xer0x

где / как получить json@ xer0x?
Gus

@Gus ой, чтобы получить jsonинструмент, перейдите на github.com/trentm/json
xer0x

Ответы:


157

Начиная с версии 1.4 это возможно с помощью *оператора. Когда даны два объекта, он рекурсивно объединит их. Например,

jq -s '.[0] * .[1]' file1 file2

Важно: обратите внимание на -s (--slurp)флаг, который помещает файлы в один массив.

Вы бы получили:

{
  "value1": 200,
  "timestamp": 1382461861,
  "value": {
    "aaa": {
      "value1": "v1",
      "value2": "v2",
      "value3": "v3",
      "value4": 4
    },
    "bbb": {
      "value1": "v1",
      "value2": "v2",
      "value3": "v3"
    },
    "ccc": {
      "value1": "v1",
      "value2": "v2"
    },
    "ddd": {
      "value3": "v3",
      "value4": 4
    }
  },
  "status": 200
}

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

jq -s '.[0] * .[1] | {value: .value}' file1 file2

Или предположительно несколько более эффективный (потому что он не объединяет никакие другие значения):

jq -s '.[0].value * .[1].value | {value: .}' file1 file2

2
ПРИМЕЧАНИЕ : -sфлаг важен, поскольку без него два объекта не входят в массив.
Джон Моралес

1
@SimoKinnunen Здесь мы объединяем два файла json. Возможно ли иметь 1 переменную json и другой файл json. Я пробовал, но, похоже, у меня не работает!
Jayesh Dhandha

Если отдельные файлы отсортированы по ключу, можно ли сохранить порядок в итоговом файле?
Лев,

@SimoKinnunen Я использую эту команду: «jq -s 'add' config.json other / *. Json», но когда я делаю «cat config.json», он не объединяется. Как я могу вернуть результат в файл?
Ренато Бибиано,

63

Использование jq -s add:

$ echo '{"a":"foo","b":"bar"} {"c":"baz","a":0}' | jq -s add
{
  "a": 0,
  "b": "bar",
  "c": "baz"
}

Это считывает все тексты JSON из stdin в массив ( jq -sделает это), а затем «сокращает» их.

( addопределяется как def add: reduce .[] as $x (null; . + $x);, который выполняет итерацию по значениям входного массива / объекта и добавляет их. Добавление объекта == слияние.)


4
Можно ли при таком подходе выполнить рекурсивное слияние (оператор *)?
Дэйв Фостер,

1
@DaveFoster Да, примерно так reduce .[] as $x ({}; . * $x)- см. Также ответ jrib .
Chriki

Это помогло мне объединить два файла json с помощью Ansible и jq. Спасибо.
Фелипе Альварес

35

Кто знает, нужно ли вам это еще, но вот решение.

Как только вы дойдете до --slurpопции, это будет просто!

--slurp/-s:
    Instead of running the filter for each JSON object in the input,
    read the entire input stream into a large array and run the filter just once.

Тогда +оператор сделает то, что вы хотите:

jq -s '.[0] + .[1]' config.json config-user.json

(Примечание: если вы хотите объединить внутренние объекты вместо того, чтобы просто перезаписывать левые файловые объекты правыми, вам нужно будет сделать это вручную)


19

Вот версия, которая рекурсивно работает (с использованием *) на произвольном количестве объектов:

echo '{"A": {"a": 1}}' '{"A": {"b": 2}}' '{"B": 3}' | jq --slurp 'reduce .[] as $item ({}; . * $item)'
{
  "A": {
    "a": 1,
    "b": 2
  },
  "B": 3
}

2
Отличный ответ. Хорошо работает при объединении всех файлов в каталоге:jq -s 'reduce .[] as $item ({}; . * $item)' *.json
Джон Элмор 08

7

Во-первых, {"value": .value} можно сократить до {value}.

Во-вторых, опция --argfile (доступная в jq 1.4 и jq 1.5) может представлять интерес, так как позволяет избежать использования опции --slurp.

Собрав их вместе, два объекта в двух файлах можно объединить указанным ниже образом:

$ jq -n --argfile o1 file1 --argfile o2 file2 '$o1 * $o2 | {value}'

Флаг '-n' указывает jq не читать из stdin, поскольку здесь вводятся параметры --argfile.


2
jq устарел --argileдля--slurpfile
Дэвид Грумс

3

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

jq -rs 'reduce .[] as $item ({}; . * $item)' file1.json file2.json file3.json ... file10.json

или это для любого количества файлов

jq -rs 'reduce .[] as $item ({}; . * $item)' ./*.json

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.