Как выбрать элементы в 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