jq — Как выбирать объекты на основе «белого списка» значений свойств

#jq

#jq #белый список

Вопрос:

Поскольку пример стоит тысячи слов, скажем, у меня есть следующий поток JSON:

 {"a": 0, "b": 1}
{"a": 2, "b": 2}
{"a": 7, "b": null}
{"a": 3, "b": 7}
  

Как я могу сохранить все объекты, для которых .b свойство является одним из [1, 7] (на самом деле список намного длиннее, поэтому я не хочу этого делать select(.b == 1 or .b == 7) ). Я ищу что-то вроде этого: select(.b in [1, 7]) , но я не смог найти то, что я ищу на странице руководства.

Ответ №1:

Это $value in $collection может быть достигнуто с помощью шаблона select($value == $collection[]) . Более эффективной альтернативой было бы select(any($value == $collection[]; .)) Поэтому ваш фильтр должен быть таким:

 [1, 7] as $whitelist | select(any(.b == $whitelist[]; .))
  

Наличие массива в переменной имеет свои преимущества, поскольку позволяет легко изменять белый список с помощью аргументов.

 $ jq --argjson whitelist '[2, 7]' 'select(any(.b == $whitelist[]; .))'
  

Комментарии:

1. Первоначальный вопрос относился к потоку, а не к массиву, и в этом случае вам не нужно было бы использовать map .

2. Также обратите внимание, что [1, 7][] может быть выражено как (1, 7) .

3. Первоначально в вопросе указывалось, что входными данными был массив, но это было изменено после того, как я ответил.

4. Да, я не прав, отредактировав вопрос, как только я увидел ваш ответ, я просто хотел сделать вопрос более целенаправленным. @SantiagoLapresta где документация для (1, 7) конструкции, кажется, я не могу найти ее на странице руководства.

5. @foo: Ключ в том, что с помощью запятых выражение выдает несколько значений. При использовании [] в массиве это выражение также выдает несколько значений. Я предполагаю, что соответствующий раздел в руководстве находится на [ , ] . [1, 2, 3][] эквивалентно 1, 2, 3 .

Ответ №2:

Следующий подход с использованием index/1 аналогичен тому, который был первоначально запрошен («.b в [1, 7]»), и может быть заметно быстрее, чем использование .[] внутри select , если белый список большой.

Если ваш jq поддерживает —argjson:

 jq --argjson w '[1,7]' '. as $in | select($w | index($in.b))'
  

В противном случае:

 jq --arg w '[1,7]' '. as $in | ($w|fromjson) as $w | select($w | index($in.b))'
  

или:

 jq '. as $in | select([1, 7] | index($in.b))'
  

Обновить

30 января 2017 года была добавлена встроенная функция с именем IN для эффективной проверки того, содержится ли объект JSON в потоке. Его также можно использовать для эффективной проверки членства в массиве. Например, приведенный выше вызов с помощью —argjson может быть упрощен до:

 jq --argjson w '[1,7]' 'select( .b | IN($w[]) )'
  

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

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