2014-09-03 14 views
6

Mam plik z liniami takiego:Jak wybrać elementy w JQ na podstawie wartości w tablicy

{"items":["blue","green"]} 
{"items":["yellow","green"]} 
{"items":["blue","pink"]} 

Jak mogę używać jq aby wybrać i pokazać tylko wartości JSON, które mają „niebieski” w ich tablica "items"?

więc wyjście byłoby:

{"items":["blue","green"]} 
{"items":["blue","pink"]} 
+0

@Tomalak, przepraszam. "Lines of json" jest tym, co powinienem napisać. – K2xL

+0

@ Tomalak, o jaki kod pytasz? Nie ma kodu. – K2xL

+0

Tak, zapomnij. Myliłem się. Usuwam komentarze. – Tomalak

Odpowiedz

4

Mimo to, czego na pewno działa, byłoby bardziej poprawne użycie contains. Unikałbym tego użycia, ponieważ może to prowadzić do zamieszania. index("blue") to 0 i nie można uznać, że wartość prawdy i może oczekiwać, że zostanie wykluczone z wyników.

Zastanów się nad wykorzystaniem tego filtru zamiast:

select(.items | contains(["blue"])) 

Ma to tę dodatkową zaletę, że będzie działać, jeśli chciał przedmiotów z więcej niż jednym meczu, po prostu dodając do tablicy.

Jak zaznaczono w komentarzach, nie jest to poprawne. Ciągi są porównywane przy użyciu dopasowywania podłańcuchowego (tutaj rekurencyjnie używa się contains).

Z perspektywy czasu, contains nie działało tak jak myślałem. Korzystanie z index działa, ale osobiście bym go nie używał. Jest coś o tym, żeby dowiedzieć się, czy przedmiot jest w kolekcji, szukając jego indeksu, który wydaje mi się błędny. Korzystanie z contains ma dla mnie więcej sensu, ale w świetle tych informacji nie byłoby w tym przypadku idealnym rozwiązaniem.


Oto alternatywa, która powinna działać poprawnie:

select([.items[] == "blue"] | any) 

Albo bardziej skalowalny sposób, jeśli chcesz być w stanie dopasować kolejne wartości:

select(.items as $values | ["blue", "yellow"] | map([$values[] == .] | any) | all) 
+0

Ta odpowiedź jest niepoprawna. Chociaż w niektórych przypadkach może to (niebezpiecznie) zadziałać, może również skutkować fałszywymi pozytywami. "zawiera" jest wyłącznie wyszukiwaniem podciąganym. Kontrprzykład: jq -n '["foobar", "bar", "baz"] | zawiera (["foo"]) "Wyniki są prawdziwe. Porównaj z: jq -n '["foobar", "bar", "baz"] | (index ("foo") == null | not) ', który poprawnie daje wynik fałszywy. –

+0

Dzięki za wskazanie, że na Will, nie zdawałem sobie sprawy, że uruchomił on filtr rekurencyjnie dla tablic. Jestem pewien, że jest sposób, aby to zrobić, ale wciąż jest skalowalny. –

+0

Nie wiem, czy byłoby to skalowalne, czy nie, ponieważ podejrzewam, że wyszukiwanie iteracyjne jest wykonywane we wszystkich przypadkach, ale użyłem też wcześniej: 'jq -n '[" foobar "," bar "," baz " ] | [. [] | wybierz (. == "foobar")] | length> 0'' co najmniej posiada * potencjał * do równoległego wyszukiwania. –

3

Okazało się odpowiedź

jq 'select(.items | index("blue"))' 
0

dniu 30 stycznia, 2017, dodano wbudowane o nazwie IN dla efektywnego testowania, czy jednostka JSON jest zawarta w strumieniu. Może być również używany do efektywnego testowania członkostwa w tablicy. W niniejszym przypadku, odpowiednie wykorzystanie byłoby:

select(.items as $items | "blue" | IN($items[])) 

Jeśli jq nie posiada IN/1, a następnie tak długo, jak jq ma first/1, można użyć tej równoważną definicję:

def IN(s): . as $in | first(if (s == $in) then true else empty end) // false; 

(W praktyce, index/1 jest zwykle wystarczająco szybki, ale jego implementacja (jq 1.5 i wersje do co najmniej lipca 2017) jest nieoptymalna.)

Powiązane problemy