Selecting key name of parent objects when child object contains a specific key

Given the following JSON containing 3 variables:

{
  "variables": {
    "AWS_ROLE": "DevOpsAccessRole",
    "AWS_REGION": {
      "description": "AWS region",
      "value": "us-west-2",
      "options": [
        "us-west-2",
        "us-east-1"
      ]
    },
    "ENVIRONMENT": {
      "description": "Environment to deploy to",
      "value": "dev",
      "options": [
        "dev",
        "qa",
        "prod"
      ]
    }
  }
}

My goal is to select only the variable names containing the description field.

So the desired output is (don’t care about the order):

AWS_REGION
ENVIRONMENT

AWS_ROLE should be left out since it does not contain the description key.

I’ve initially tried:

jq -r '.variables | keys []'

Which returns:

AWS_ROLE
AWS_REGION
ENVIRONMENT

But I’m stuck removing the ones without description.

Also tried:

jq -r '.variables |..| select(.description?)'

but the problem here is that I loose access to the variable names.

How can I do this in jq ?

>Solution :

Use to_entries to get simultaneous access to both the .key and the .value, test the existence of a (sub-)key using has, and use ? to suppress errors if it is not an object (thus has no key, and would error out). Using the -r flag gives you a raw-text output.

jq -r '.variables | to_entries[] | select(.value | has("description")?).key'
AWS_REGION
ENVIRONMENT

Demo


The same technique using keys, iterated over and stored in a variable:

jq -r '.variables | keys[] as $k | .[$k] | select(has("description")?) | $k'

Demo

Leave a Reply