Come unire 2 oggetti JSON da 2 file usando jq?


124

Sto usando gli strumenti jq (jq-json-processor) nello script della shell per analizzare json.

Ho 2 file JSON e voglio unirli in un unico file

Qui il contenuto dei 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
        }
    }
}

Risultato atteso

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

Provo molte combinazioni ma l'unico risultato che ottengo è il seguente, che non è il risultato atteso:

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

Utilizzando questo comando:

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

1
Hai provato jsontool? github.com/trentm/json
Nano Taboada

Non ancora, darò un'occhiata. Thx
Janfy

Per farlo con l' jsonuso:cat f1 f2 | json --deep-merge
xer0x

dove / come si ottiene json@ xer0x?
Gus

@Gus oh, per ottenere lo jsonstrumento vai su github.com/trentm/json
xer0x

Risposte:


155

Dalla 1.4 questo è ora possibile con l' *operatore. Quando vengono forniti due oggetti, li unirà ricorsivamente. Per esempio,

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

Importante: nota il -s (--slurp)flag, che inserisce i file nello stesso array.

Ti farebbe:

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

Se vuoi sbarazzarti anche degli altri tasti (come il risultato atteso), un modo per farlo è questo:

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

O presumibilmente un po 'più efficiente (perché non unisce altri valori):

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

2
NOTA : il -sflag è importante in quanto senza di esso i due oggetti non sono in un array.
John Morales

1
@SimoKinnunen Qui stiamo unendo due file JSON. È possibile avere 1 variabile json e un altro file json. Ho provato ma sembra non funzionare per me!
Jayesh Dhandha

Se i singoli file vengono ordinati in base a una chiave, è possibile mantenere l'ordine nel file risultante?
Leone

@SimoKinnunen sto usando questo comando: "jq -s 'add' config.json other / *. Json" ma quando eseguo un "cat config.json" non viene unito. Come posso rimettere l'output nel file?
Renato Bibiano

63

Usa jq -s add:

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

Questo legge tutti i testi JSON dallo stdin in un array (lo jq -sfa) quindi li "riduce".

( addè definito come def add: reduce .[] as $x (null; . + $x);, che itera sui valori / object dell'array di input e li aggiunge. Object addition == merge.)


4
È possibile eseguire l'unione ricorsiva (operatore *) con questo approccio?
Dave Foster,

1
@DaveFoster Sì, con qualcosa di simile reduce .[] as $x ({}; . * $x)- vedi anche la risposta di jrib .
Chriki

Questo mi ha aiutato a unire due file json usando Ansible e jq. Grazie.
Felipe Alvarez

35

Chissà se ne hai ancora bisogno, ma ecco la soluzione.

Una volta raggiunta l' --slurpopzione, è facile!

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

Quindi l' +operatore farà quello che vuoi:

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

(Nota: se vuoi unire gli oggetti interni invece di sovrascrivere semplicemente quelli del file sinistro con quelli del file destro, dovrai farlo manualmente)


19

Ecco una versione che funziona in modo ricorsivo (utilizzando *) su un numero arbitrario di oggetti:

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

2
Bella risposta. Funziona bene quando si uniscono tutti i file in una directory:jq -s 'reduce .[] as $item ({}; . * $item)' *.json
John Ellmore,

7

Innanzitutto, {"value": .value} può essere abbreviato solo in {value}.

In secondo luogo, l'opzione --argfile (disponibile in jq 1.4 e jq 1.5) può essere interessante in quanto evita di dover usare l'opzione --slurp.

Mettendoli insieme, i due oggetti nei due file possono essere combinati nel modo specificato come segue:

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

Il flag '-n' dice a jq di non leggere dallo stdin, poiché gli input provengono dalle opzioni --argfile qui.


2
jq è stato ritirato --argileper--slurpfile
David Groomes

3

Questo può essere utilizzato per unire qualsiasi numero di file specificato nel comando:

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

o questo per qualsiasi numero di file

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.