Selecionar objetos com base no valor da variável no objeto usando jq

236

Eu tenho o seguinte arquivo json:

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

Estou usando jq e quero obter os elementos "name" dos objetos em que 'location' é 'Stockholm'.

Eu sei que posso obter todos os nomes

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

Mas não consigo descobrir como imprimir apenas certos objetos, dado o valor de uma subchave (aqui "location" : "Stockholm").

Daniel
fonte

Respostas:

341

Adaptado desta postagem no Processing JSON with jq , você pode usar o select(bool)seguinte:

$ jq '.[] | select(.location=="Stockholm")' json
{
  "location": "Stockholm",
  "name": "Walt"
}
{
  "location": "Stockholm",
  "name": "Donald"
}
Daniel
fonte
30
Como obter o pai 'FOO', 'BAR', 'BAZ'?
Spazm
184

Para obter um fluxo apenas dos nomes:

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

produz:

"Donald"
"Walt"

Para obter um fluxo de pares correspondentes (nome da chave, atributo "nome")), considere:

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

Resultado:

["FOO","Donald"]
["BAR","Walt"]
pico
fonte
Ele quer o objeto inteiro com base na localização: "Não consigo descobrir como imprimir apenas certos objetos, dado o valor de uma subchave"
Fo.
2
Você não precisa do pipe após a seleção: $ jq '. [] | select (.location == "Stockholm"). name 'json
Deepak
Fazer a namevariável-chave (usar uma função shell com $1como parâmetro) não funciona: termux-contact-list |jq -r '.[] | select(.name=="$1")|.number'. Eu chamo assim cool_fn Name1. No entanto, isso funciona:termux-contact-list |jq -r '.[] | select(.name=="Name1")|.number'
Timo
Aqui está a solução, se você gosta da variável.
Timo
27

Eu tinha uma pergunta semelhante: E se você quisesse o formato do objeto original de volta (com nomes de chave, por exemplo, FOO, BAR)?

Jq fornece to_entriese from_entriesconverte entre objetos e matrizes de pares de valores-chave. Que junto com mapa seleção

Essas funções são convertidas entre um objeto e uma matriz de pares de valores-chave. Se to_entries receber um objeto, para cada entrada k: v na entrada, a matriz de saída incluirá {"key": k, "value": v}.

from_entries faz a conversão oposta e with_entries (foo) é uma abreviação de to_entries | mapa (foo) | from_entries, útil para executar alguma operação em todas as chaves e valores de um objeto. from_entries aceita chave, chave, nome, nome, valor e valor como chaves.

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

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

Usando a with_entriesabreviação, isso se torna:

jq15 < json 'with_entries(select(.value.location=="Stockholm"))'
{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}
spazm
fonte
1
Uma coisa que continua me mordendo é que você precisa se lembrar de que, ao usar with_entries(), geralmente também deseja usar .valuena selectcláusula. Isso ocorre porque a to_entriesmacro converte as entradas fornecidas em .keye .valueemparelha, o que também acontece com with_entries.
27419 Jaakko