Alex
Alex

Reputation: 2805

jq get the value of x based on y in a complex json file

jq strikes again. Trying to get the value of DATABASES_DEFAULT based on the name in a json file that has a whole lot of names and I'm completely lost.

My file looks like the following (output of an aws ecs describe-task-definition) only much more complex; I've stripped this to the most basic example I can where the structure is still intact.

{
    "taskDefinition": {
        "status": "bar", 
        "family": "bar2",  
        "volumes": [], 
        "taskDefinitionArn": "bar3", 
        "containerDefinitions": [
            {
                "dnsSearchDomains": [], 
                "environment": [
                    {
                        "name": "bar4", 
                        "value": "bar5"
                    }, 
                    {
                        "name": "bar6", 
                        "value": "bar7"
                    },  
                    {
                        "name": "DATABASES_DEFAULT", 
                        "value": "foo"
                    }
                ], 
                "name": "baz", 
                "links": []
            },
            {
                "dnsSearchDomains": [], 
                "environment": [
                    {
                        "name": "bar4", 
                        "value": "bar5"
                    }, 
                    {
                        "name": "bar6", 
                        "value": "bar7"
                    },  
                    {
                        "name": "DATABASES_DEFAULT", 
                        "value": "foo2"
                    }
                ], 
                "name": "boo", 
                "links": []
            }
        ], 
        "revision": 1
    }
}

I need the value of DATABASES_DEFAULT where the name is baz. Note that there are a lot of keypairs with name, I'm specifically talking about the one outside of environment.

I've been tinkering with this but only got this far before realizing that I don't understand how to access nested values.

jq '.[] | select(.name==DATABASES_DEFAULT) | .value'

which is returning

jq: error: DATABASES_DEFAULT/0 is not defined at <top-level>, line 1:
.[] | select(.name==DATABASES_DEFAULT) | .value
jq: 1 compile error

Obviously this a) doesn't work, and b) even if it did, it's independant of the name value. My thought was to return all the db defaults and then identify the one with baz, but I don't know if that's the right approach.

Upvotes: 1

Views: 436

Answers (2)

Thor
Thor

Reputation: 47199

I like to think of it as digging down into the structure, so first you open the outer layers:

.taskDefinition.containerDefinitions[]

Now select the one you want:

select(.name =="baz")

Open the inner structure:

.environment[]

Select the desired object:

select(.name == "DATABASES_DEFAULT")

Choose the key you want:

.value

Taken together:

parse.jq

.taskDefinition.containerDefinitions[] |
select(.name =="baz")                  |
.environment[]                         |
select(.name == "DATABASES_DEFAULT")   |
.value

Run it like this:

<infile jq -f parse.jq

Output:

"foo"

Upvotes: 2

chepner
chepner

Reputation: 532093

The following seems to work:

.taskDefinition.containerDefinitions[] |
  select(
    select(
     .environment[] | .name == "DATABASES_DEFAULT"
    ).name == "baz"
  )

The output is the object with the name key mapped to "baz".

$ jq '.taskDefinition.containerDefinitions[] | select(select(.environment[]|.name == "DATABASES_DEFAULT").name=="baz")' tmp.json
{
  "dnsSearchDomains": [],
  "environment": [
    {
      "name": "bar4",
      "value": "bar5"
    },
    {
      "name": "bar6",
      "value": "bar7"
    },
    {
      "name": "DATABASES_DEFAULT",
      "value": "foo"
    }
  ],
  "name": "baz",
  "links": []
}

Upvotes: 1

Related Questions