Sélectionner des objets en fonction de la valeur de la variable dans l'objet à l'aide de jq

236

J'ai le fichier json suivant:

{
    "FOO": {
        "name": "Donald",
        "location": "Stockholm"
    },
    "BAR": {
        "name": "Walt",
        "location": "Stockholm"
    },
    "BAZ": {
        "name": "Jack",
        "location": "Whereever"
    }
}

J'utilise jq et je veux obtenir les éléments "nom" des objets où "emplacement" est "Stockholm".

Je sais que je peux obtenir tous les noms par

cat json | jq .[] | jq ."name"
"Jack"
"Walt"
"Donald"

Mais je ne peux pas comprendre comment imprimer uniquement certains objets, étant donné la valeur d'une sous-clé (ici "location" : "Stockholm").

Daniel
la source

Réponses:

341

Adapté de cet article sur le traitement de JSON avec jq , vous pouvez utiliser select(bool)ce qui suit :

$ jq '.[] | select(.location=="Stockholm")' json
{
  "location": "Stockholm",
  "name": "Walt"
}
{
  "location": "Stockholm",
  "name": "Donald"
}
Daniel
la source
30
Comment pourrais-je obtenir le parent «FOO», «BAR», «BAZ»?
spazm
184

Pour obtenir un flux contenant uniquement les noms:

$ jq '.[] | select(.location=="Stockholm") | .name' json

produit:

"Donald"
"Walt"

Pour obtenir un flux de paires correspondantes (nom de clé, attribut "nom"), envisagez:

$ jq -c 'to_entries[]
        | select (.value.location == "Stockholm")
        | [.key, .value.name]' json

Production:

["FOO","Donald"]
["BAR","Walt"]
de pointe
la source
Il veut que l'objet entier soit basé sur l'emplacement: "Je ne peux pas comprendre comment imprimer seulement certains objets, étant donné la valeur d'une sous-clé"
Fo.
2
Vous n'avez pas besoin du tuyau après la sélection: $ jq '. [] | select (.location == "Stockholm"). name 'json
Deepak
Faire la namevariable clé (utilisez une fonction shell avec $1comme paramètre) ne fonctionne pas: termux-contact-list |jq -r '.[] | select(.name=="$1")|.number'. Je l'appelle comme cool_fn Name1. Cependant, cela fonctionne:termux-contact-list |jq -r '.[] | select(.name=="Name1")|.number'
Timo
Voici la solution si vous l'aimez variable.
Timo
27

J'avais une question similaire similaire: que se passerait-il si vous vouliez retrouver le format d'objet d'origine (avec des noms de clé, par exemple FOO, BAR)?

Jq fournit to_entrieset from_entriesconvertit entre les objets et les tableaux de paires clé-valeur. Cela avec mapautour de la sélection

Ces fonctions convertissent entre un objet et un tableau de paires clé-valeur. Si to_entries reçoit un objet, alors pour chaque entrée k: v dans l'entrée, le tableau de sortie inclut {"key": k, "value": v}.

from_entries fait la conversion opposée, et with_entries (foo) est un raccourci pour to_entries | carte (foo) | from_entries, utile pour effectuer certaines opérations sur toutes les clés et valeurs d'un objet. from_entries accepte la clé, la clé, le nom, le nom, la valeur et la valeur comme clés.

jq15 < json 'to_entries | map(select(.value.location=="Stockholm")) | from_entries'

{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}

En utilisant la with_entriessténographie, cela devient:

jq15 < json 'with_entries(select(.value.location=="Stockholm"))'
{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}
spazm
la source
1
Une chose qui me mord toujours, c'est que vous devez vous rappeler que lors de l'utilisation with_entries(), vous souhaitez généralement utiliser également .valuedans la selectclause. Cela est dû au fait que la to_entriesmacro convertit les entrées données en .keyet .valuepaire, ce qui se produit également avec with_entries.
Jaakko