249 votes

Comment fusionner 2 objets JSON à partir de 2 fichiers en utilisant jq?

J'utilise les outils jq (jq-json-processor) dans un script shell pour analyser du json.

J'ai 2 fichiers json et je veux les fusionner en un seul fichier unique

Voici le contenu des fichiers:

fichier1

{
    "valeur1": 200,
    "horodatage": 1382461861,
    "valeur": {
        "aaa": {
            "valeur1": "v1",
            "valeur2": "v2"
        },
        "bbb": {
            "valeur1": "v1",
            "valeur2": "v2"
        },
        "ccc": {
            "valeur1": "v1",
            "valeur2": "v2"
        }
    }
}

fichier2

{
    "statut": 200,
    "horodatage": 1382461861,
    "valeur": {
        "aaa": {
            "valeur3": "v3",
            "valeur4": 4
        },
        "bbb": {
            "valeur3": "v3"
        },      
        "ddd": {
            "valeur3": "v3",
            "valeur4": 4
        }
    }
}

résultat attendu

{
    "valeur": {
        "aaa": {
            "valeur1": "v1",
            "valeur2": "v2",
            "valeur3": "v3",
            "valeur4": 4
        },
        "bbb": {
            "valeur1": "v1",
            "valeur2": "v2",
            "valeur3": "v3"
        },
        "ccc": {
            "valeur1": "v1",
            "valeur2": "v2"
        },
        "ddd": {
            "valeur3": "v3",
            "valeur4": 4
        }
    }
}

J'ai essayé beaucoup de combinaisons mais le seul résultat que j'obtiens est le suivant, qui n'est pas le résultat attendu:

{
  "ccc": {
    "valeur2": "v2",
    "valeur1": "v1"
  },
  "bbb": {
    "valeur2": "v2",
    "valeur1": "v1"
  },
  "aaa": {
    "valeur2": "v2",
    "valeur1": "v1"
  }
}
{
  "ddd": {
    "valeur4": 4,
    "valeur3": "v3"
  },
  "bbb": {
    "valeur3": "v3"
  },
  "aaa": {
    "valeur4": 4,
    "valeur3": "v3"
  }
}

En utilisant cette commande:

jq -s '.[].valeur' fichier1 fichier2

10voto

peak Points 71

Tout d'abord, {"value": .value} peut être abrégé simplement en {value}.

Ensuite, l'option --argfile (disponible dans jq 1.4 et jq 1.5) peut être intéressante car elle évite d'avoir à utiliser l'option --slurp.

En combinant ces deux éléments, les deux objets des deux fichiers peuvent être combinés de la manière spécifiée comme suit :

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

Le drapeau '-n' indique à jq de ne pas lire depuis stdin, puisque les entrées viennent des options --argfile ici.

Remarque sur --argfile

Le manuel de jq déconseille l'utilisation de --argfile car ses sémantiques sont non triviales : si le fichier d'entrée spécifié contient exactement une entité JSON, alors cette entité est lue telle quelle ; sinon, les éléments du flux sont enveloppés dans un tableau.

Si vous êtes mal à l'aise avec l'utilisation de --argfile, il existe plusieurs alternatives que vous pouvez envisager. En le faisant, soyez assuré que l'utilisation de --slurpfile n'entraîne pas les inefficacités de l'option en ligne de commande -s lorsque cette dernière est utilisée avec plusieurs fichiers.

10voto

dngray Points 101

Cela peut être utilisé pour fusionner n'importe quel nombre de fichiers spécifiés sur la commande :

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

ou ceci pour n'importe quel nombre de fichiers

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

5voto

Jon Points 1211

Je n'ai pas voulu supprimer la clé précédente non unique dans mes objets

jq -n '{a:1, c:2}, {b:3, d:4}, {a:5,d:6}' |
jq -s 'map(to_entries)|flatten|group_by(.key)|map({(.[0].key):map(.value)|add})|add'
{
  "a": 6,
  "b": 3,
  "c": 2,
  "d": 10
}

ou sinon, si vous vouliez simplement conserver un tableau des valeurs, supprimez le "add" après l'extraction de la valeur map(.value)|̶a̶d̶d̶

jq -n '{a:1, c:2}, {b:3, d:4}, {a:5,d:6}' |
jq -s 'map(to_entries)|flatten|group_by(.key)|map({(.[0].key):map(.value)})|add'
{
  "a": [1, 5],
  "b": [3],
  "c": [2],
  "d": [4, 6]
}

Essayez de supprimer chaque partie de la commande et voyez comment chaque étape modifie le tableau d'objets... c'est à dire exécutez ces étapes et voyez comment la sortie change

map(to_entries)
map(to_entries)|flatten
map(to_entries)|flatten|group_by(.key)
map(to_entries)|flatten|group_by(.key)|map({(.[0].key):map(.value)})
map(to_entries)|flatten|group_by(.key)|map({(.[0].key):map(.value)})|add

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X