479 Stimmen

Jq: wie man ein Array von Objekten basierend auf Werten in einem inneren Array filtert.

Gegeben diese Eingabe:

[
  {
    "Id": "cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b",
    "Names": [
      "condescending_jones",
      "loving_hoover"
    ]
  },
  {
    "Id": "186db739b7509eb0114a09e14bcd16bf637019860d23c4fc20e98cbe068b55aa",
    "Names": [
      "foo_data"
    ]
  },
  {
    "Id": "a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19",
    "Names": [
      "jovial_wozniak"
    ]
  },
  {
    "Id": "76b71c496556912012c20dc3cbd37a54a1f05bffad3d5e92466900a003fbb623",
    "Names": [
      "bar_data"
    ]
  }
]

Ich versuche, einen Filter mit jq zu konstruieren, der alle Objekte zurückgibt, deren Ids "data" nicht im inneren Names Array enthalten, wobei die Ausgabe zeilenweise erfolgt. Für die obigen Daten möchte ich folgende Ausgabe erhalten:

cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b
a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19

Ich denke, ich bin damit etwas nah dran:

(. - select(.Names[] contains("data"))) | .[] .Id

aber der select Filter ist nicht richtig und es kompiliert nicht (bekomme einen Fehler: Syntaxfehler, unerwartetes IDENT).

706voto

Ganz nah dran! In deinem select-Ausdruck musst du ein Senkrechtstrich (|) vor contains verwenden.

Dieser Filter erzeugt die erwartete Ausgabe.

. - map(select(.Names[] | contains ("data"))) | .[] .Id

Das jq Cookbook enthält ein Beispiel für die Syntax.

Objekte basierend auf dem Inhalt eines Schlüssels filtern

Zum Beispiel möchte ich nur Objekte haben, deren Genre-Schlüssel "house" enthält.

$ json='[{"genre":"deep house"}, {"genre": "progressive house"}, {"genre": "dubstep"}]'
$ echo "$json" | jq -c '.[] | select(.genre | contains("house"))'
{"genre":"deep house"}
{"genre":"progressive house"}

Colin D fragt, wie die JSON-Struktur des Arrays erhalten bleiben kann, sodass die endgültige Ausgabe ein einzelnes JSON-Array ist, anstatt einer Abfolge von JSON-Objekten.

Der einfachste Weg ist, den gesamten Ausdruck in einem Array-Konstruktor zu umschließen:

$ echo "$json" | jq -c '[ .[] | select( .genre | contains("house")) ]'
[{"genre":"deep house"},{"genre":"progressive house"}]

Sie können auch die map-Funktion verwenden:

$ echo "$json" | jq -c 'map(select(.genre | contains("house")))'
[{"genre":"deep house"},{"genre":"progressive house"}]

map packt das Eingabearray aus, wendet den Filter auf jedes Element an und erstellt ein neues Array. Mit anderen Worten: map(f) ist äquivalent zu [.[]|f].

38voto

jq170727 Punkte 11532

Hier ist eine weitere Lösung, die any/2 verwendet

map(select(any(.Names[]; contains("data"))|not)|.Id)[]

mit den Beispieldaten und der Option -r ergibt es:

cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b
a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19

7voto

Raghu Dodda Punkte 1405

Filter (demo):

.[] | select( [ .Names[] | contains("data") ] | any) | .Id

Erklärung:

  • .[] entpackt das Array, sodass wir über jedes Element im Array iterieren
  • select() behält nur die Elemente, bei denen die Bedingung erfüllt ist. Die Bedingung lautet, dass mindestens ein Name im .Names-Array dieses Elements das Wort data enthält.
    • .Names[] | contains ("data") entpackt das .Names-Array jedes Elements und überprüft, ob jeder Name den Text data enthält. Zu diesem Zeitpunkt haben wir ein Array von booleschen Werten derselben Länge wie ein .Names-Array dieses Elements.
    • [.Names[] | contains ("data") ] | any nimmt dieses Array von booleschen Werten und reduziert es zu einem einzelnen booleschen Wert, da die any-Funktion überprüft, ob mindestens ein Element in diesem Array true ist. Das select verwendet diesen Wert als Bedingung effektiv.
  • .Id pflückt das Id-Attribut der durchgekommenen Elemente.

3voto

Leia Renée Punkte 51

Die folgende jq-map-select-Ausdruck ergibt das beabsichtigte Ergebnis:

aws ecr describe-images \
  --registry-id  \
  --repository-name  \
  --region  \
  --no-cli-pager \
  --filter tagStatus=TAGGED \
| jq '.imageDetails | map(select(.imageTags[] | contains ("version_tag")))'

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X