Jq kullanarak 2 dosyadan 2 JSON nesnesi nasıl birleştirilir?


124

Jq kullanıyorum ayrıştırma json için kabuk komut dosyası araçları (jq-json işlemcili).

2 json dosyam var ve bunları tek bir dosyada birleştirmek istiyorum

İşte dosyaların içeriği:

dosya1

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

dosya2

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

Beklenen Sonuç

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

Çok fazla kombinasyon deniyorum ama aldığım tek sonuç şudur ki bu beklenen sonuç değildir:

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

Bu komutu kullanarak:

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

1
Jsontool denedin mi? github.com/trentm/json
Nano Taboada

Henüz değil, bir göz atacağım. Thx
Janfy

Bunu kullanarak yapmak jsoniçin:cat f1 f2 | json --deep-merge
xer0x

json@ xer0x'i nereden / nasıl alırsınız ?
Gus

@Gus oh, jsonaracı almak için github.com/trentm/json
xer0x

Yanıtlar:


155

1.4'ten beri bu artık *operatörle mümkündür . İki nesne verildiğinde, onları yinelemeli olarak birleştirir. Örneğin,

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

Önemli: -s (--slurp)Dosyaları aynı diziye yerleştiren bayrağa dikkat edin.

Seni alır mıydı:

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

Diğer anahtarlardan da kurtulmak istiyorsanız (beklenen sonucunuz gibi), bunu yapmanın bir yolu şudur:

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

Ya da muhtemelen biraz daha etkilidir (çünkü diğer değerleri birleştirmez):

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

2
NOT : -sbayrak önemlidir, çünkü onsuz iki nesne bir dizide değildir.
John Morales

1
@SimoKinnunen Burada iki json dosyasını birleştiriyoruz. 1 json değişkeni ve başka bir json dosyasına sahip olmak mümkün mü? Denedim ama benim için çalışmıyor gibi görünüyor!
Jayesh Dhandha

Tek tek dosyalar bir anahtara göre sıralanırsa, ortaya çıkan dosyadaki sırayı korumak mümkün müdür?
Leo

@SimoKinnunen Bu komutu kullanıyorum: "jq -s 'add' config.json diğer / *. Json" ama bir "cat config.json" yaptığımda birleştirilmiyor. Çıktıyı dosyaya nasıl geri koyabilirim?
Renato Bibiano

63

Kullanım jq -s add:

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

Bu, tüm JSON metinlerini stdin'den bir diziye okur (jq -s bunu yapar) ve sonra onları "azaltır".

( addOlarak tanımlanır def add: reduce .[] as $x (null; . + $x);giriş dizinin / nesnenin değerleri üzerinden dolaşır ve. Nesne ek == birleştirme ekler ki,.)


4
Bu yaklaşımla yinelemeli birleştirme (* operatörü) yapmak mümkün mü?
Dave Foster

1
@DaveFoster Evet, benzer bir şeyle reduce .[] as $x ({}; . * $x)- jrib'in cevabına da bakın .
Chriki

Bu, Ansible ve jq kullanarak iki json dosyasını birleştirmeme yardımcı oldu. Teşekkürler.
Felipe Alvarez

35

Hala ihtiyacınız olup olmadığını kim bilebilir, ama işte çözüm.

Bir kez --slurp geldiğinizde, çok kolay!

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

Sonra + operatör istediğinizi yapacak:

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

(Not: Soldaki dosya olanların üzerine doğru dosya olanların üzerine yazmak yerine iç nesneleri birleştirmek istiyorsanız, bunu manuel olarak yapmanız gerekecektir)


19

Burada *, rastgele sayıda nesne üzerinde özyinelemeli (kullanarak ) çalışan bir sürüm bulunmaktadır :

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

2
Mükemmel cevap. Bir dizindeki tüm dosyaları birleştirirken iyi çalışıyor:jq -s 'reduce .[] as $item ({}; . * $item)' *.json
John Ellmore

7

İlk olarak, {"değer": .value} yalnızca {değer} olarak kısaltılabilir.

İkinci olarak, --argfile seçeneği (jq 1.4 ve jq 1.5'te mevcuttur), --slurp seçeneğini kullanmak zorunda kalmadığından ilgi çekici olabilir.

Bunları bir araya getirerek, iki dosyadaki iki nesne aşağıdaki gibi belirtilen şekilde birleştirilebilir:

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

'-N' bayrağı jq'ye stdin'den okumamasını söyler, çünkü girdiler buradaki --argfile seçeneklerinden gelir.


2
jq onaylamamıştır --argileiçin--slurpfile
David Groomes

3

Bu, komutta belirtilen herhangi bir sayıda dosyayı birleştirmek için kullanılabilir:

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

veya bu herhangi bir sayıda dosya için

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.