Seleccione objetos basados ​​en el valor de la variable en el objeto usando jq

236

Tengo el siguiente archivo json:

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

Estoy usando jq y quiero obtener los elementos de "nombre" de los objetos donde 'ubicación' es 'Estocolmo'.

Sé que puedo obtener todos los nombres por

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

Pero no puedo entender cómo imprimir solo ciertos objetos, dado el valor de una subclave (aquí "location" : "Stockholm").

Daniel
fuente

Respuestas:

341

Adaptado de esta publicación sobre Procesamiento de JSON con jq , puede usar lo select(bool)siguiente:

$ jq '.[] | select(.location=="Stockholm")' json
{
  "location": "Stockholm",
  "name": "Walt"
}
{
  "location": "Stockholm",
  "name": "Donald"
}
Daniel
fuente
30
¿Cómo obtendría el padre 'FOO', 'BAR', 'BAZ'?
spazm
184

Para obtener una secuencia de solo los nombres:

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

produce:

"Donald"
"Walt"

Para obtener una secuencia de pares correspondientes (nombre clave, atributo "nombre"), considere:

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

Salida:

["FOO","Donald"]
["BAR","Walt"]
pico
fuente
Quiere todo el objeto según la ubicación: "No puedo entender cómo imprimir solo ciertos objetos, dado el valor de una subclave"
Fo.
2
No necesita la tubería después de la selección: $ jq '. [] | select (.location == "Stockholm"). name 'json
Deepak
Haciendo la namevariable clave (utilizar una función de cáscara con $1como parámetro) no funciona: termux-contact-list |jq -r '.[] | select(.name=="$1")|.number'. Yo lo llamo así cool_fn Name1. Sin embargo, esto funciona:termux-contact-list |jq -r '.[] | select(.name=="Name1")|.number'
Timo
Aquí está la solución si te gusta variable.
Timo
27

Tenía una pregunta similar relacionada: ¿Qué pasaría si quisieras recuperar el formato original del objeto (con nombres clave, por ejemplo, FOO, BAR)?

Jq proporciona to_entriesy from_entriespara convertir entre objetos y matrices de pares clave-valor. Eso junto con maptodo el selecto

Estas funciones se convierten entre un objeto y una matriz de pares clave-valor. Si to_entries pasa un objeto, entonces para cada entrada k: v en la entrada, la matriz de salida incluye {"clave": k, "valor": v}.

from_entries realiza la conversión opuesta, y with_entries (foo) es una abreviatura de to_entries | mapa (foo) | from_entries, útil para realizar algunas operaciones con todas las claves y valores de un objeto. from_entries acepta clave, clave, nombre, nombre, valor y valor como claves.

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

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

Usando la with_entriestaquigrafía, esto se convierte en:

jq15 < json 'with_entries(select(.value.location=="Stockholm"))'
{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}
Spazm
fuente
1
Una cosa que sigue mordiéndome es que debes recordar que cuando lo usas with_entries(), generalmente también quieres usarlo .valueen la selectcláusula. Esto se debe a que la to_entriesmacro convierte las entradas dadas .keyy se .valueempareja, lo que también sucede con with_entries.
Jaakko