Как выбрать элементы в JQ на основе значения в массиве

У меня есть файл с такими строками:

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

Как я могу использовать jq для выбора и отображения только значений JSON, имеющих "синий" в их массиве "items"?

Таким образом, выход будет:

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

Ответ 1

Хотя то, что вы, безусловно, работаете, было бы правильнее использовать contains. Я бы избегал этого использования, поскольку это может привести к путанице. index("blue") - 0, и никто не считает это правдоподобным значением и может ожидать, что он будет исключен из результатов.

Вместо этого используйте этот фильтр:

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

Это имеет дополнительное преимущество, что оно будет работать, если вам нужны элементы с несколькими совпадениями, просто добавив больше в массив. Забастовкa >

Как указано в комментариях, это не совсем правильно. Строки сравниваются с использованием подстроки (contains используется рекурсивно) здесь.

В ретроспективе contains не сработало, как я думал. Использование index работает, но лично я бы не использовал его. Есть что-то в том, чтобы выяснить, есть ли элемент в коллекции, ища его индекс, который мне не нравится. Использование contains имеет для меня больше смысла, но в свете этой информации в этом случае оно не будет идеальным.


Вот альтернатива, которая должна работать правильно:

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

Или для более масштабируемого способа, если вы хотите иметь возможность сопоставлять больше значений:

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

Ответ 2

Нашел ответ

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

Ответ 3

30 января 2017 г. была добавлена встроенная функция IN для эффективной проверки наличия в потоке сущности JSON. Он также может быть использован для эффективного тестирования членства в массиве. В данном случае соответствующее использование будет:

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

Если ваш jq не имеет IN/1, то, пока ваш jq имеет first/1, вы можете использовать это эквивалентное определение:

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

любой /0

Использование any/0 здесь относительно неэффективно, например, по сравнению с использованием any/0:

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

(На практике index/1 обычно достаточно быстрый, но его реализация в настоящее время (jq 1.5 и версии по крайней мере до июля 2017 года) является неоптимальной.)

Ответ 4

Мне нужно было использовать "регулярное выражение" для той же ситуации объектов. (В другом контексте, конечно). Я пишу код, потому что я не нашел решения для своих нужд на этих страницах. Это может быть полезно для кого-то.

Например, чтобы соответствовать синему цвету, используя регулярное выражение:

jq 'select(.items[]|test("bl.*"))' yourfile.json

jqPlay