1

Let's say I have the following JSON output:

{
 "Stacks": [
        {
            "StackName": "hello-world",
            "Tags": [
                {
                    "Key": "environment",
                    "Value": "sandbox"
                },
                {
                    "Key": "Joe Shmo",
                    "Value": "Dev"
                }
            ]
        },
        {
            "StackName": "hello-man",
            "Tags": [
                {
                    "Key": "environment",
                    "Value": "live"
                },
                {
                    "Key": "Tandy",
                    "Value": "Dev"
                }
            ]
        }
    ]
}

How would I write a jq query to grab all StackNames for stacks that do NOT have a Tags value "Key": "Joe Shmo"? So the result would return simply hello-man.

peak
  • 105,803
  • 17
  • 152
  • 177
Mike
  • 339
  • 1
  • 3
  • 14

2 Answers2

1
.Stacks[]
| select( any(.Tags[]; .Key == "Joe Shmo" ) | not)
| .StackName

This checks for equality efficiently (any has short-circuit semantics), whereas contains would check for containment.

peak
  • 105,803
  • 17
  • 152
  • 177
  • I'm checking if `.Tags` contains an object with the _exact_ key "Joe Shmo". At least I think my code is doing that – hek2mgl Jan 11 '19 at 01:25
  • omg! I now see what you mean. Seriously, this is prone to be misunderstood. Especially since the manual doesn't mention it. If I would be the author I would place a red box into the manual: CAREFUL: this function is broken – hek2mgl Jan 11 '19 at 01:37
  • PS: Unf. SO doesn't allow to delete an accepted answer. – hek2mgl Jan 11 '19 at 01:46
0

Using contains, like this:

jq -r '.Stacks[]|select(.Tags|contains([{"Key": "Joe Shmo"}])|not).StackName'

Note: -r removes the quotes from output, otherwise jq would print "hello-man" (within double quotes)

hek2mgl
  • 152,036
  • 28
  • 249
  • 266