Peter Lutz Peter Lutz - 1 month ago 6
JSON Question

jq select attribute if any array element satisfies a condition

With the help of jq i would like to select all addresses of nodes that have at least one required=true in their attribute list. The result list should have unique items.

Here is my Json:

{
"nodes": [
{
"address":"127.0.0.1",
"attributes": [
{
"id":"abc",
"required":true
},
{
"id":"def",
"required":true
},
{
"id":"ghi",
"required":false
}
]
},
{
"address":"127.0.0.2",
"attributes": [
{
"id":"abc",
"required":false
},
{
"id":"def",
"required":false
}
]
}
]
}


I first tried with:

jq '.nodes[] | select(.attributes[].required == true) | .address'


This produces:

"127.0.0.1"
"127.0.0.1"


So it gets the address for every required=true field it finds in the attributes section. How to make the result list unique? There is also a unique keyword in jq, but I couldn't figure out how this could help me.

Answer

Using unique is safe but it does require sorting, which may not be necessary. In your particular case, for example, the repetition is an artifact of the jq query. Consider using any instead (or as well), as it more precisely captures the intention ("at least one"), as well as having "short-circuit" semantics (i.e., it stops searching once the condition is true):

$ jq '.nodes[]
| select( any(.attributes[]; .required == true))
| .address' input.json

Output:

"127.0.0.1"

You can always add unique if necessary.