Tim Smith
Tim Smith

Reputation: 133

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"
        }
    ]
}

Upvotes: 13

Views: 8999

Answers (2)

jq170727
jq170727

Reputation: 14665

Here is a solution which uses indices

.Subnets[] | select(.Tags | indices({Key:"Name", Value:"TheName"}) != [])

Upvotes: 1

peak
peak

Reputation: 116780

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?'

Upvotes: 17

Related Questions