Як об'єднати 2 об’єкти JSON з 2-х файлів за допомогою jq?


123

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

У мене є 2 json-файли і хочу об'єднати їх в один унікальний файл

Тут вміст файлів:

файл1

{
    "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
Нано Табоада

Ще немає, я погляну. Thx
Janfy

Для цього jsonвикористовуйте:cat f1 f2 | json --deep-merge
xer0x

звідки / як ви отримуєте json@ xer0x?
Гас

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

Відповіді:


154

З 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
Джон Елмор

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
David Groomes

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.