Reputation: 32354
I'm using JQ to filter a list of things, and then for each found thing - reformat it to a single string by extracting values from sub-keys.
The problem is that is one of the sub-keys is missing, the entire line is omitted.
Consider the following example document:
{
"items": [
{
"id": "A",
"active": true,
"tags": [
{ "name": "foo", "value": 1 }
]
},
{
"id": "B",
"active": true,
"tags": [
{ "name": "foo", "value":1 },
{"name": "bar", "value":2}
]
},
{
"id": "C",
"active": false,
"tags": [
{ "name": "foo", "value":1 },
{ "name": "baz", "value":3 }
]
}
]
}
Now I want to select all active items, and create for each a single line describing the item's ID as well as the value of both its foo
and bar
tags.
Initially I've done something like this:
jq -r '
.items[] |
select ( .active == true ) |
( .id + " -> [" +
( .tags[] | select( .name == "foo" ) | .value | tostring ) +
", " +
( .tags[] | select( .name == "bar" ) | .value | tostring ) +
"]"
)
'
But because bar
is only included in item B
, the line for item A
gets filtered out.
Is there a way to make the sub-select optional so that if the select fails, I get an empty string or something like that?
Upvotes: 2
Views: 1111
Reputation: 116870
You could patch your query using if ... then ... else ... end
or perhaps //
, but it would be better to address some other issues as well, e.g. as follows:
.items[]
| select ( .active == true )
| .id + " -> ["
+ (.tags | map(select(.name == "foo") | .value) | join(";"))
+ ", "
+ (.tags | map(select(.name == "bar") | .value) | join(";"))
+ "]"
With jq version 1.5 or earlier, you would need to add a call to tostring
, or to use string interpolation, e.g.
.items[]
| select ( .active == true )
| .id
+ " -> [\(.tags | map(select(.name == "foo") | "\(.value)") | join(";") ), "
+ "\(.tags | map(select(.name == "bar") | "\(.value)" ) | join(";"))"
+ "]"
first
and string interpolation.items[]
| select ( .active == true )
| (first(.tags[] | select(.name == "foo") | .value) // "") as $v
| (first(.tags[] | select(.name == "bar") | .value) // "") as $w
| "\(.id) -> [\($v), \($w)]"
Using string interpolation circumvents the potential need to use tostring
.
Upvotes: 2