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
Janfy
quelle
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
Simo Kinnunen
quelle
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.)

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

FiloSottile
quelle
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
}
jrib
quelle
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.

Gipfel
quelle
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

dngray
quelle