Comment filtrer un tableau d'objets basé sur des valeurs dans un tableau intérieur avec jq?

compte tenu de cette entrée:

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

j'essaie de construire un filtre avec jq qui retourne tous les objets avec Id s que ne contiennent" des données "dans le tableau intérieur Names , avec la sortie étant newline-separated. Pour les données ci-dessus, la sortie que je voudrais est

cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b
a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19

je pense que je suis un peu près ceci:

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

mais le select filter n'est pas correct et ne compile pas (get error: syntax error, unexpected IDENT ).

134
demandé sur peak 2014-11-02 19:23:32

2 réponses

très proche! Dans votre expression select , vous devez utiliser un tuyau ( | ) avant contains .

ce filtre produit la sortie attendue.

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

le JQ Cookbook a un exemple de syntaxe.

filtrer les objets à partir du contenu d'une clé

E. G., Je ne veux que des objets dont la clé de genre contient "house".

$ 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 demande comment préserver la structure JSON du tableau, de sorte que la sortie finale est un seul tableau JSON plutôt qu'un flux d'objets JSON.

la manière la plus simple est d'envelopper toute l'expression dans un constructeur de tableaux:

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

vous pouvez également utiliser la fonction map:

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

map décompose le tableau d'entrée, applique le filtre à chaque élément, et crée un nouveau tableau. En d'autres termes, map(f) est équivalent à [.[]|f] .

218
répondu Iain Samuel McLean Elder 2017-05-23 12:02:56

Voici une autre solution qui utilise des /2

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

avec les données de l'échantillon et l'option -r qu'il produit

cb94e7a42732b598ad18a8f27454a886c1aa8bbba6167646d8f064cd86191e2b
a4b7e6f5752d8dcb906a5901f7ab82e403b9dff4eaaeebea767a04bac4aada19
8
répondu jq170727 2017-08-31 00:53:24