Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selecting from complex nested JSON data in JQ

Tags:

json

jq

any

I have JSON data like this:

{
  "profiles": {
    "auto_scaler": [
      {
        "auto_scaler_group_name": "myasg0",
        "auto_scaler_group_options": {
          ":availability_zones": ["1a", "1b", "1c"],
          ":max_size": 1,
          ":min_size": 1,
          ":subnets": ["a", "b", "c"],
          ":tags": [
            {":key": "Name", ":value": "app0" },
            {":key": "env", ":value": "dev" },
            {":key": "role", ":value": "app" },
            {":key": "domain", ":value": "example.com" },
            {":key": "fonzi_app", ":value": "true"},
            {":key": "vpc", ":value": "nonprod"}
          ]
        },
        "dns_name": "fonz1"
      },
      {
        "auto_scaler_group_name": "myasg1",
        "auto_scaler_group_options": {
          ":availability_zones": ["1a", "1b", "1c"],
          ":max_size": 1,
          ":min_size": 1,
          ":subnets": ["a", "b", "c"],
          ":tags": [
            {":key": "Name", ":value": "app1" },
            {":key": "env", ":value": "dev" },
            {":key": "role", ":value": "app" },
            {":key": "domain", ":value": "example.com" },
            {":key": "bozo_app", ":value": "true"},
            {":key": "vpc", ":value": "nonprod"}
          ]
        },
        "dns_name": "bozo1"
      }
    ]
  }
}

I want to write a jq query to firstly select the Hash element in the Array at .profiles.auto_scaler whose Array of Hashes at .auto_scaler_group_options.tags contains Hashes containing a ":key" key whose value contains "fonzi" and a ":value" key whose value is exactly true and then return the value of the key dns_name.

In the example, the query would simply return "fonz1".

Does anyone know how to do this, if it is possible, using jq?

like image 218
Alex Harvey Avatar asked Jun 29 '26 00:06

Alex Harvey


1 Answers

In brief, yes.

In long:

.profiles.auto_scaler[]
| .dns_name as $name
| .auto_scaler_group_options
| select( any(.[":tags"][];
             (.[":key"] | index("fonzi")) and (.[":value"] == "true")) )
| $name

The output of the above is:

"fonz1"

The trick here is to extract the candidate .dns_name before diving more deeply into your "complex nested JSON".

An alternative

If your jq does not have any, you could (in this particular case) get away without it by replacing the select expression above with:

 select( .[":tags"][]
         | (.[":key"] | index("fonzi")) and (.[":value"] == "true") )

Be warned, though, that the semantics of the two expressions are slightly different. (Homework exercise: what is the difference?)

If your jq doesn't have any and if you want the semantics of any, then you could easily roll your own, or simply upgrade :-)

like image 198
peak Avatar answered Jul 01 '26 06:07

peak