问题
I'm using jq 1.4.
I trying to select elements when VPCZoneIdentifier exists in my $selected_subnets
(bash variable).
selected_subnets="valueA valueB"
input='{"elements":[
{"name": "nameA", "VPCZoneIdentifier": "valueA"},
{"name": "nameB", "VPCZoneIdentifier": "valueB"},
{"name": "nameC", "VPCZoneIdentifier": "valueC"}
]}'
test
and match
fn are only available on v1.5.
回答1:
This is a little tricky, but it can be done with reduce
. The whole thing could look like this:
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))]'
The first part makes a JSON array from the shell list:
$ echo "\"$selected_subnets\"" | jq -c -M 'split(" ")'
["valueA","valueB"]
The second part uses the reduce
filter to compare the .VPCZoneIdentifier
property with all elements of this array. With the selected_subnets_json
variable expanded into it, the filter looks as follows:
.elements = [
.elements[] |
select(.VPCZoneIdentifier as $id |
[ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))
]
That is to say, the elements
property is overwritten with those elements of it that match the selection criterium
.VPCZoneIdentifier as $id | [ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))
Of this the first part remembers the VPCZoneIdentifier
as $id
(because .
will shortly mean something entirely different), and
[ "valueA", "valueB" ] | reduce .[] as $v (false; . or $id == $v))
is an or-reduction of the subnet array. It expands to false or $id == "valueA" or $id == "valueB"
in this case.
If you prefer to have it all in one go, you could write
echo "$input" | jq -M '.elements = [.elements[] | select(.VPCZoneIdentifier as $id | ("'"$selected_subnets"'" | split(" ")) | reduce .[] as $v (false; . or $id == $v))]'
This works essentially the same way, except the splitting of $selected_subnets
is done inline.
回答2:
You can set variables from the command line to be available in your queries using the --arg
option. You can then filter out the elements using the select
filter. Given an array of values, you could do a "value in array"
test doing the following:
value == (array[])
So your filter would have the following structure:
.elements | map(
select(
.VPCZoneIdentifier == ($subnets | split(" ")[])
)
)
Putting it all together with your variables:
$ echo $input | jq --arg subnets "$selected_subnets" '.elements | map(select(.VPCZoneIdentifier == ($subnets | split(" ")[])))'
[
{
"name": "nameA",
"VPCZoneIdentifier": "valueA"
},
{
"name": "nameB",
"VPCZoneIdentifier": "valueB"
}
]
来源:https://stackoverflow.com/questions/29142185/jq-select-when-attribute-value-exists-in-a-bash-array