JQ: выберите, когда значение атрибута существует в массиве bash

Я использую JQ 1.4. Я пытаюсь выбрать элементы, когда VPCZoneIdentifier существует в моем $selected_subnets (переменная bash).

selected_subnets="valueA valueB"

input='{"elements":[
           {"name": "nameA", "VPCZoneIdentifier": "valueA"}, 
           {"name": "nameB", "VPCZoneIdentifier": "valueB"}, 
           {"name": "nameC", "VPCZoneIdentifier": "valueC"}
       ]}'

test а также match fn доступны только на v1.5.

2 ответа

Решение

Это немного сложно, но это может быть сделано с reduce, Все это может выглядеть так:

selected_subnets_json=$(echo "\"$selected_subnets\"" | jq -c -M 'split(" ")')
echo "$input" | jq -M '.elements = [.elements[] | select(.VPCZoneIdentifier as $id | '"$selected_subnets_json"' | reduce .[] as $v (false; . or $id == $v))]'

Первая часть делает массив JSON из списка оболочки:

$ echo "\"$selected_subnets\"" | jq -c -M 'split(" ")'
["valueA","valueB"]

Вторая часть использует reduce фильтр для сравнения .VPCZoneIdentifier свойство со всеми элементами этого массива. С selected_subnets_json переменная, развернутая в нее, фильтр выглядит следующим образом:

.elements = [
  .elements[] |
    select(.VPCZoneIdentifier as $id |
           [ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))
]

То есть elements свойство перезаписывается теми элементами, которые соответствуют критерию выбора

.VPCZoneIdentifier as $id | [ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))

Об этом первая часть помнит VPCZoneIdentifier как $id (так как . будет означать что-то совсем другое) и

[ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))

является или сокращением массива подсети. Расширяется до false or $id == "valueA" or $id == "valueB" в этом случае.

Если вы предпочитаете иметь все это за один раз, вы можете написать

echo "$input" | jq -M '.elements = [.elements[] | select(.VPCZoneIdentifier as $id | ("'"$selected_subnets"'" | split(" ")) | reduce .[] as $v (false; . or $id == $v))]'

Это работает в основном так же, за исключением разделения $selected_subnets делается встроенным

Вы можете установить переменные из командной строки, чтобы они были доступны в ваших запросах, используя --arg вариант. Затем вы можете отфильтровать элементы, используя select фильтр. Учитывая массив значений, вы можете сделать "value in array" сделайте следующее:

value == (array[])

Таким образом, ваш фильтр будет иметь следующую структуру:

.elements | map(
    select(
        .VPCZoneIdentifier == ($subnets | split(" ")[])
    )
)

Собираем все это вместе с вашими переменными:

$ echo $input | jq --arg subnets "$selected_subnets" '.elements | map(select(.VPCZoneIdentifier == ($subnets | split(" ")[])))'
[
  {
    "name": "nameA",
    "VPCZoneIdentifier": "valueA"
  },
  {
    "name": "nameB",
    "VPCZoneIdentifier": "valueB"
  }
]
Другие вопросы по тегам