Tim Smith Tim Smith - 1 month ago 26
JSON Question

Using jq to select a parent by searching child key/value pair

Using jq, how do I select a parent object if it contains a child object that meets two filter requirements?

In this example I want to select all Subnets elements that have a child tag with key "Name" and value "TheName". My example has two subnets. The first has "TheName" in the wrong key. The second subnet has the name/value pair I am looking for. i.e.

"Key": "Name", "Value": "TheName"


The following selects a subnet with the specified value in one of the tags but not the pair. It returns both subnets instead of only the second subnet.

jq '.Subnets[] | select(.Tags[].Value=="TheName")' output


How do I use jq to select only the subnets that have the name/value pair I am looking for?

{
"Subnets": [
{
"VpcId": "vpc-12345678",
"SubnetId": "subnet-1234567a",
"Tags": [
{
"Key": "IgnoreThis",
"Value": "TheName"
},
{
"Key": "Name",
"Value": "NotTheName"
}
]
},
{
"VpcId": "vpc-12345678",
"SubnetId": "subnet-1234567b",
"Tags": [
{
"Key": "IgnoreThis",
"Value": "ignore"
},
{
"Key": "Name",
"Value": "TheName"
}
]
}
]
}


The desired output would be:

{
"VpcId": "vpc-12345678",
"SubnetId": "subnet-1234567b",
"Tags": [
{
"Key": "IgnoreThis",
"Value": "ignore"
},
{
"Key": "Name",
"Value": "TheName"
}
]
}

Answer

Assuming your jq has any/2, a simple and efficient solution would be:

.Subnets[]
| select( any (.Tags[]; .Key == "Name" and .Value == "TheName") )

This produces the output you want, so I won't repeat it here.

If your jq does not have any/2, I'd suggest upgrading, but if that's inconvenient or not an option, you could use this def:

def any(f;g): reduce f as $i (false; . or ($i|g));

p.s. any(str; cond) can be read as: 'Is there any element, e, in the stream, str, such that e|cond has a value other than null or false?'

Comments