AWS CLI and JMESPath filter and select on nested properties
Asked Answered
P

2

7

I want to use the CLI tool, to retrieve the distribution-id of a CloudFront distribution with a specific cname/alias.

This is what I came up with:

aws cloudfront list-distributions --query "DistributionList.Items[?Aliases.Items!='null']|DistributionList.Items[?contains(Aliases.Items,'cname.cdn.mycompany.com') == 'true'].{Id:Id}"

I'm not an expert at JMESPath, and I don't understand why my query doesn't return a result. A distribution with the specified domain as alias exists.

Partitive answered 23/2, 2016 at 9:34 Comment(0)
P
17

You're very close! A few things though:

  • null is not 'null'
  • After the pipe you'll be working with the results of the first expression
  • like null, true is not a string (== true is also redundant)

jmespath.org Has a live editor that you can use to test out expressions. Here's a simplified json we can use to test this case:

{
    "DistributionList": {
        "Items": [
            {
                "Id": "foo",
                "Aliases": {
                    "Quantity": 1,
                    "Items": [
                        "cname.cdn.mycompany.com"
                    ]
                }
            },
            {
                "Id": "bar",
                "Aliases": {
                    "Quantity": 1,
                    "Items": [
                        "cname.cdn.othercompany.com"
                    ]
                }
            },
            {
                "Id": "baz",
                "Aliases": {
                    "Quantity": 0
                }
            }
        ]
    }
}

Let's start with the first part of the expression. The only fix you need is taking the quotes off null:

DistributionList.Items[?Aliases.Items!=null]

Which will successfully filter out elements without Items under Alias. Here is what you would get back if you stopped here, and what you'll have to work with after the pipe:

[
  {
    "Id": "foo",
    "Aliases": {
      "Quantity": 1,
      "Items": [
        "cname.cdn.mycompany.com"
      ]
    }
  },
  {
    "Id": "bar",
    "Aliases": {
      "Quantity": 1,
      "Items": [
        "cname.cdn.othercompany.com"
      ]
    }
  }
]

Note that there is no DistributionList.Items anymore.

So now we want to filter for a specific CNAME. Lets leave out the tautology == true.

[?contains(Aliases.Items, 'cname.cdn.mycompany.com')]

So the full expression now is:

DistributionList.Items[?Aliases.Items!=null] | [?contains(Aliases.Items, 'cname.cdn.mycompany.com')]

And your result is the successfully filtered list:

[
  {
    "Id": "foo",
    "Aliases": {
      "Quantity": 1,
      "Items": [
        "cname.cdn.mycompany.com"
      ]
    }
  }
]

Now if you want the Id's of the matching elements, just add .Id to that last expression. If you know there will only be one, you can just select that element with another pipe and [0].

DistributionList.Items[?Aliases.Items!=null] | [?contains(Aliases.Items, 'cname.cdn.mycompany.com')].Id | [0]

And you get the Id you want!

"foo"
Pewter answered 24/2, 2016 at 16:7 Comment(1)
When perfoming the query on command line I had to change the quotes around domain name to ` `Prince
C
1

To add, I found it out without the pipe.

aws cloudfront list-distributions --query "DistributionList.Items[?contains(Aliases.Items, 'cname.cdn.mycompany.com')].Id" --output text

Cantharides answered 3/6, 2021 at 7:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.