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

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

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


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)


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
}

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.


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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.