Wybierz obiekty na podstawie wartości zmiennej w obiekcie za pomocą jq

236

Mam następujący plik json:

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

Korzystam z jq i chcę uzyskać elementy „name” obiektów, w których „location” to „Stockholm”.

Wiem, że mogę uzyskać wszystkie nazwiska

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

Ale nie mogę wymyślić, jak wydrukować tylko niektóre obiekty, biorąc pod uwagę wartość podklucza (tutaj "location" : "Stockholm").

Daniel
źródło

Odpowiedzi:

341

Zaadaptowane z tego postu na temat Przetwarzanie JSON za pomocą jq , możesz użyć select(bool)następującego:

$ jq '.[] | select(.location=="Stockholm")' json
{
  "location": "Stockholm",
  "name": "Walt"
}
{
  "location": "Stockholm",
  "name": "Donald"
}
Daniel
źródło
30
Jak zdobyć rodzica „FOO”, „BAR”, „BAZ”?
spazm
184

Aby uzyskać strumień samych nazw:

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

produkuje:

"Donald"
"Walt"

Aby uzyskać strumień odpowiednich par (nazwa klucza, atrybut „nazwa”), rozważ:

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

Wynik:

["FOO","Donald"]
["BAR","Walt"]
szczyt
źródło
Chce całego obiektu na podstawie lokalizacji: „Nie mogę wymyślić, jak wydrukować tylko niektóre obiekty, biorąc pod uwagę wartość podklucza”
Fo.
2
Po zaznaczeniu nie potrzebujesz rury: $ jq '. [] | wybierz (.location == "Sztokholm"). nazwa 'json
Deepak
Dokonywanie namekluczową zmienną (użyć funkcji z powłoki $1jako parametr) nie działa: termux-contact-list |jq -r '.[] | select(.name=="$1")|.number'. Nazywam to tak cool_fn Name1. Działa to jednak:termux-contact-list |jq -r '.[] | select(.name=="Name1")|.number'
Timo
Oto rozwiązanie, jeśli podoba Ci się zmienna.
Timo,
27

Miałem podobne podobne pytanie: co zrobić, jeśli chcesz odzyskać oryginalny format obiektu (z nazwami kluczy, np. FOO, BAR)?

Jq zapewnia to_entriesi from_entrieskonwertuje między obiektami i tablicami para-wartość. To wraz z mapcałym wybranym

Funkcje te konwertują między obiektem a tablicą par klucz-wartość. Jeśli to_entries zostanie przekazany obiekt, to dla każdego wpisu k: v na wejściu tablica wyjściowa zawiera {„klucz”: k, „wartość”: v}.

from_entries dokonuje odwrotnej konwersji, a with_entries (foo) jest skrótem dla to_entries | mapa (foo) | from_entries, przydatne do wykonywania niektórych operacji na wszystkich kluczach i wartościach obiektu. from_entries akceptuje klucz, klucz, nazwę, nazwę, wartość i wartość jako klucze.

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

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

Używając with_entriesstenografii, staje się to:

jq15 < json 'with_entries(select(.value.location=="Stockholm"))'
{
  "FOO": {
    "name": "Donald",
    "location": "Stockholm"
  },
  "BAR": {
    "name": "Walt",
    "location": "Stockholm"
  }
}
spazm
źródło
1
Jedną rzeczą, która mnie gryzie, jest to, że musisz pamiętać, że podczas używania with_entries()zwykle chcesz również użyć .valuew selectklauzuli. Wynika to z tego, że to_entriesmakro konwertuje podane wpisy .keyi łączy .value, co również dzieje się z with_entries.
Jaakko