Wählen Sie Objekte basierend auf dem Wert der Variablen im Objekt mit jq aus

236

Ich habe die folgende JSON-Datei:

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

Ich benutze jq und möchte die "Namen" -Elemente der Objekte erhalten, bei denen "Ort" "Stockholm" ist.

Ich weiß, dass ich alle Namen von bekommen kann

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

Angesichts des Werts eines Unterschlüssels (hier "location" : "Stockholm") kann ich jedoch nicht herausfinden, wie nur bestimmte Objekte gedruckt werden sollen .

Daniel
quelle

Antworten:

341

In Anlehnung an diesen Beitrag zur Verarbeitung von JSON mit jq können Sie Folgendes verwenden select(bool):

$ jq '.[] | select(.location=="Stockholm")' json
{
  "location": "Stockholm",
  "name": "Walt"
}
{
  "location": "Stockholm",
  "name": "Donald"
}
Daniel
quelle
30
Wie würde ich die Eltern 'FOO', 'BAR', 'BAZ' bekommen?
Spazm
184

So erhalten Sie einen Stream mit nur den Namen:

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

produziert:

"Donald"
"Walt"

Beachten Sie Folgendes, um einen Stream entsprechender Paare (Schlüsselname, Attribut "Name") zu erhalten:

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

Ausgabe:

["FOO","Donald"]
["BAR","Walt"]
Gipfel
quelle
Er möchte, dass das gesamte Objekt nach Standort sortiert wird: "Ich kann angesichts des Werts eines Unterschlüssels nicht herausfinden, wie nur bestimmte Objekte gedruckt werden sollen"
Fo.
2
Sie benötigen die Pipe nach der Auswahl nicht: $ jq '. [] | Wählen Sie (.location == "Stockholm"). name 'json
Deepak
Das Erstellen der nameSchlüsselvariablen (Verwenden einer Shell-Funktion mit $1als Parameter) funktioniert nicht : termux-contact-list |jq -r '.[] | select(.name=="$1")|.number'. Ich nenne es wie cool_fn Name1. Dies funktioniert jedoch:termux-contact-list |jq -r '.[] | select(.name=="Name1")|.number'
Timo
Hier ist die Lösung, wenn Sie es variabel mögen.
Timo
27

Ich hatte eine ähnliche verwandte Frage: Was wäre, wenn Sie das ursprüngliche Objektformat zurückhaben wollten (mit Schlüsselnamen, z. B. FOO, BAR)?

Jq bietet to_entriesund from_entrieskonvertiert zwischen Objekten und Schlüssel-Wert-Paar-Arrays. Das zusammen mit maprund um die Auswahl

Diese Funktionen werden zwischen einem Objekt und einem Array von Schlüssel-Wert-Paaren konvertiert. Wenn to_entries ein Objekt übergeben wird, enthält das Ausgabearray für jeden k: v-Eintrag in der Eingabe {"key": k, "value": v}.

from_entries führt die entgegengesetzte Konvertierung durch und with_entries (foo) ist eine Abkürzung für to_entries | Karte (foo) | from_entries, nützlich, um alle Schlüssel und Werte eines Objekts zu bearbeiten. from_entries akzeptiert Schlüssel, Schlüssel, Name, Name, Wert und Wert als Schlüssel.

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

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

Mit der with_entriesKurzform wird dies:

jq15 < json 'with_entries(select(.value.location=="Stockholm"))'
{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}
spazm
quelle
1
Eine Sache, die mich immer wieder beißt, ist, dass Sie sich daran erinnern müssen, dass Sie bei der Verwendung with_entries()normalerweise auch .valuein der selectKlausel verwenden möchten . Dies liegt daran, dass das to_entriesMakro die angegebenen Einträge in .keyund .valuePair konvertiert , was auch bei der Fall ist with_entries.
Jaakko