Wie füge ich 2 JSON-Objekte aus 2 Dateien mit jq zusammen?


123

Ich verwende die jq- Tools (jq-json-Prozessor) im Shell-Skript, um json zu analysieren.

Ich habe 2 JSON-Dateien und möchte sie zu einer einzigen Datei zusammenführen

Hier der Inhalt von Dateien:

Datei1

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

Datei2

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

erwartetes Ergebnis

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

Ich versuche viel Kombination, aber das einzige Ergebnis, das ich bekomme, ist das folgende, was nicht das erwartete Ergebnis ist:

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

Mit diesem Befehl:

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

1
Haben Sie jsontool ausprobiert? github.com/trentm/json
— Nano Taboada

Noch nicht, ich werde einen Blick darauf werfen. Thx
— Janfy

Um dies mit jsonVerwendung zu tun :cat f1 f2 | json --deep-merge
— xer0x

jsonWoher / Wie bekommst du @ xer0x?
— Gus

@ Gus oh, um das jsonTool zu bekommen , gehen Sie zu github.com/trentm/json
— xer0x

Antworten:


154

Seit 1.4 ist dies nun mit dem *Bediener möglich. Wenn zwei Objekte angegeben werden, werden sie rekursiv zusammengeführt. Beispielsweise,

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

Wichtig: Beachten Sie das -s (--slurp)Flag, mit dem Dateien im selben Array abgelegt werden.

Würde dich bekommen:

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

Wenn Sie auch die anderen Schlüssel entfernen möchten (wie das erwartete Ergebnis), können Sie dies folgendermaßen tun:

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

Oder das vermutlich etwas effizientere (weil es keine anderen Werte zusammenführt):

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

2
HINWEIS : Das -sFlag ist wichtig, da sich die beiden Objekte ohne es nicht in einem Array befinden.
— John Morales

1
@ SimoKinnunen Hier führen wir zwei JSON-Dateien zusammen. Ist es möglich, 1 JSON-Variable und eine andere JSON-Datei zu haben? Ich habe es versucht, aber es scheint nicht für mich zu funktionieren!
— Jayesh Dhandha

Wenn die einzelnen Dateien nach einem Schlüssel sortiert sind, kann die Reihenfolge in der resultierenden Datei beibehalten werden?
— Leo

@ SimoKinnunen Ich verwende diesen Befehl: "jq -s 'add' config.json other / *. Json", aber wenn ich eine "cat config.json" mache, wird sie nicht zusammengeführt. Wie kann ich die Ausgabe wieder in die Datei einfügen?
— Renato Bibiano

63

Verwendung jq -s add:

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

Dies liest alle JSON-Texte von stdin in ein Array ( jq -smacht das) und "reduziert" sie dann.

( addist definiert als def add: reduce .[] as $x (null; . + $x);, das über die Werte des Eingabearrays / Objekts iteriert und diese hinzufügt. Objektaddition == Zusammenführen.)


4
Ist es mit diesem Ansatz möglich, die rekursive Zusammenführung (* Operator) durchzuführen?
— Dave Foster

1
@ DaveFoster Ja, mit so etwas wie reduce .[] as $x ({}; . * $x)- siehe auch jribs Antwort .
— Chriki

Dies hat mir geholfen, zwei JSON-Dateien mit Ansible und JQ zusammenzuführen. Vielen Dank.
— Felipe Alvarez

35

Wer weiß, ob Sie es noch brauchen, aber hier ist die Lösung.

Sobald Sie die --slurpOption erreicht haben, ist es einfach!

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

Dann macht der +Bediener, was Sie wollen:

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

(Hinweis: Wenn Sie innere Objekte zusammenführen möchten, anstatt nur die linken mit den rechten zu überschreiben, müssen Sie dies manuell tun.)


19

Hier ist eine Version, die rekursiv (mit *) einer beliebigen Anzahl von Objekten arbeitet:

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

2
Gute Antwort. Funktioniert gut beim Zusammenführen aller Dateien in einem Verzeichnis:jq -s 'reduce .[] as $item ({}; . * $item)' *.json
— John Ellmore

7

Erstens kann {"value": .value} auf nur {value} abgekürzt werden.

Zweitens kann die Option --argfile (verfügbar in jq 1.4 und jq 1.5) von Interesse sein, da die Verwendung der Option --slurp vermieden wird.

Wenn Sie diese zusammenfügen, können die beiden Objekte in den beiden Dateien wie folgt kombiniert werden:

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

Das '-n'-Flag weist jq an, nicht von stdin zu lesen, da Eingaben von den Optionen --argfile hier stammen.


2
jq ist veraltet --argilefür--slurpfile
— David Groomes

3

Dies kann verwendet werden, um eine beliebige Anzahl von Dateien zusammenzuführen, die im Befehl angegeben sind:

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

oder dies für eine beliebige Anzahl von Dateien

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.