jq: How to get a value rather than boolean when matching two statements?

Viewed 44

I'm trying to extract the ARN's (.StackId) of all AWS CloudFormation stacks which match a specific string in key StackName and StackStatus of "CREATE COMPLETE" or "UPDATE_COMPLETE".

Example:

{
  "StackSummaries": [
    {
      "StackId": "arn:aws:cloudformation:us-east-1:AWS_ACCOUNT_ID:stack/some-service-name/9ad489b0-ab22-11eb-af8f-0a56fXXXX8ad",
      "StackName": "some-service-name",
      "CreationTime": "2021-05-02T08:44:28.106000+00:00",
      "StackStatus": "CREATE_COMPLETE",
      "DriftInformation": {
        "StackDriftStatus": "NOT_CHECKED"
      }
    },
    {
      "StackId": "arn:aws:cloudformation:us-east-1:AWS_ACCOUNT_ID:stack/some-service-name/44239210-9703-11eb-b085-12daXXXX6186",
      "StackName": "some-service-name",
      "TemplateDescription": "some-service-name",
      "CreationTime": "2021-04-06T18:09:45.470000+00:00",
      "LastUpdatedTime": "2021-04-13T13:09:37.683000+00:00",
      "StackStatus": "UPDATE_COMPLETE",
      "DriftInformation": {
        "StackDriftStatus": "NOT_CHECKED"
      }
    }
  ]
}

These are the commands I've tried:

aws cloudformation list-stacks --profile production |
    jq -r '.StackSummaries[] |
        select(.StackName | match("some-service-name";"i")) and
        select(.StackStatus | match("UPDATE_COMPLETE";"i")) .StackId'
aws cloudformation list-stacks --profile production |
    jq -r '.StackSummaries[] |
        select(.StackName | contains("some-service-name")) and
        select(.StackStatus | contains("UPDATE_COMPLETE")) .StackId'
aws cloudformation list-stacks --profile production |
    jq -r '.StackSummaries[] |
        select(.StackName | match("some-service-name";"i")) and
        select(.StackStatus | match("UPDATE_COMPLETE";"i") or
        select(.StackStatus | match("CREATE_COMPLETE";"i"))) .StackId'

All of the above commands return boolean value instead of the StackId itself. How can I get the StackId instead of a boolean value?

1 Answers

If you have two conditions to meet, filter twice

select(condition1) | select(condition2)

or and the conditions

select(condition1 and condition2)

As you discovered, and-ing the results of select doesn't make sense.

jq -r '
   .StackSummaries[] |
   select( 
      .StackName == "some-service-name" and (
         .StackStatus == "CREATE_COMPLETE" or
         .StackStatus == "UPDATE_COMPLETE"
       )
   ) |
   .StackId
'

jqplay


Note that | has very low precedence, so

a | b and c | d

means

a | ( b and c ) | d

Use parens if you mean

( a | b ) and ( c | d )
Related