Bagaimana cara menggabungkan 2 objek JSON dari 2 file menggunakan jq?

124

Saya menggunakan alat jq (jq-json-processor) dalam skrip shell untuk mengurai json.

Saya punya 2 file json dan ingin menggabungkannya menjadi satu file unik

Berikut isi file:

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
        }
    }
}

Hasil yang diharapkan

{
    "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
        }
    }
}

Saya mencoba banyak kombinasi tetapi satu-satunya hasil yang saya dapatkan adalah sebagai berikut, yang bukan hasil yang diharapkan:

{
  "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"
  }
}

Menggunakan perintah ini:

jq -s '.[].value' file1 file2
Janfy
sumber
1
Sudahkah Anda mencoba jsontool? github.com/trentm/json
Nano Taboada
Belum, saya akan lihat. Thx
Janfy
Untuk melakukan ini dengan json menggunakan:cat f1 f2 | json --deep-merge
xer0x
dimana / bagaimana anda mendapatkannya json @ xer0x?
Gus
@Gus oh, untuk mendapatkan jsonalatnya, buka github.com/trentm/json
xer0x

Jawaban:

155

Sejak 1.4 ini sekarang dimungkinkan dengan *operator. Ketika diberi dua objek, itu akan menggabungkannya secara rekursif. Sebagai contoh,

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

Penting: Perhatikan -s (--slurp)bendera, yang menempatkan file dalam larik yang sama.

Akan membuat Anda:

{
  "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
}

Jika Anda juga ingin menyingkirkan kunci lain (seperti hasil yang Anda harapkan), salah satu cara untuk melakukannya adalah ini:

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

Atau mungkin agak lebih efisien (karena tidak menggabungkan nilai lain):

jq -s '.[0].value * .[1].value | {value: .}' file1 file2
Simo Kinnunen
sumber
2
CATATAN : -sbendera penting karena tanpanya kedua objek tidak berada dalam array.
John Morales
1
@SimoKinnunen Di sini kami menggabungkan dua file json. Apakah mungkin memiliki 1 variabel json dan file json lainnya. Saya mencoba tetapi tampaknya tidak berhasil untuk saya!
Jayesh Dhandha
Jika file individual diurutkan berdasarkan kunci, apakah mungkin untuk mempertahankan urutan dalam file yang dihasilkan?
Leo
@SimoKinnunen Saya menggunakan perintah ini: "jq -s 'add' config.json other / *. Json" tetapi ketika saya melakukan "cat config.json" itu tidak digabungkan. Bagaimana saya bisa mengembalikan output ke file?
Renato Bibiano
63

Penggunaan jq -s add:

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

Ini membaca semua teks JSON dari stdin ke dalam array (jq -s melakukan itu) lalu "mengurangi" mereka.

( adddidefinisikan sebagai def add: reduce .[] as $x (null; . + $x);, yang melakukan iterasi di atas nilai / objek larik masukan dan menambahkannya. Penambahan objek == penggabungan.)

pengguna2259432
sumber
4
Apakah mungkin untuk melakukan penggabungan rekursif (* operator) dengan pendekatan ini?
Dave Foster
1
@DaveFoster Ya, dengan sesuatu seperti reduce .[] as $x ({}; . * $x)- lihat juga jawaban jrib .
Chriki
Ini membantu saya menggabungkan dua file json menggunakan Ansible dan jq. Terima kasih.
Felipe Alvarez
35

Siapa tahu Anda masih membutuhkannya, tetapi inilah solusinya.

Begitu Anda mendapatkan --slurpopsi, itu mudah!

--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.

Kemudian +operator akan melakukan apa yang Anda inginkan:

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

(Catatan: jika Anda ingin menggabungkan objek dalam daripada hanya menimpa file kiri dengan file kanan, Anda perlu melakukannya secara manual)

FiloSottile
sumber
19

Berikut adalah versi yang bekerja secara rekursif (menggunakan *) pada sejumlah objek yang berubah-ubah:

echo '{"A": {"a": 1}}' '{"A": {"b": 2}}' '{"B": 3}' | jq --slurp 'reduce .[] as $item ({}; . * $item)'
{
  "A": {
    "a": 1,
    "b": 2
  },
  "B": 3
}
jrib
sumber
2
Jawaban yang bagus. Berfungsi baik saat menggabungkan semua file dalam direktori:jq -s 'reduce .[] as $item ({}; . * $item)' *.json
John Ellmore
7

Pertama, {"value": .value} dapat disingkat menjadi {value}.

Kedua, opsi --argfile (tersedia di jq 1.4 dan jq 1.5) mungkin menarik karena menghindari keharusan menggunakan opsi --slurp.

Dengan menggabungkan ini, dua objek di dua file dapat digabungkan dengan cara yang ditentukan sebagai berikut:

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

Bendera '-n' memberitahu jq untuk tidak membaca dari stdin, karena input berasal dari opsi --argfile di sini.

puncak
sumber
2
jq tidak lagi digunakan --argileuntuk--slurpfile
David Groomes
3

Ini dapat digunakan untuk menggabungkan sejumlah file yang ditentukan pada perintah:

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

atau ini untuk sejumlah file

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

dngray.dll
sumber