In any version (that i've tried) of jq >= 1.5
, this works fine .
In any version of jq <= 1.4
, I get the following error:
error: syntax error, unexpected as, expecting FORMAT or QQSTRING_START
There's a lot of information around on the error: "expecting FORMAT or QQSTRING_START" , so far what I've seen has not applied here, I wonder if it's the as
that I am not implementing reliably
I can recreate the problem with this trivial code: (can be copied/pasted as is to test)
jq \ '(..|.liveBroadcastContent?'\ '| foreach . as $item (.; if $item == null then false else . end)) as $chanstatus '\ '| {location:"location", channel:"channelid", current_id:"vId", id_status:$chanstatus, url:"https://youtu.be/\("vId")"}' \ <<<'{"liveBroadcastContent":true}'
Desired result achieved on jq > 1.5
:
{
"location": "location",
"channel": "channelid",
"current_id": "vId",
"id_status": true,
"url": "https://youtu.be/vId"
}
What it's supposed to do:
liveBroadcastContent
exists in the input: then output it's value in the id_status
key liveBroadcastContent
does not exist : then output false
in the id_status
key Actual Input :
This is what goes into the program when there is a live stream present.
This is what goes into the program when there is no live streams
Hence I thought ..|.liveBroadcastContent?
was the most reliable way to basically say " If this key appears somewhere in the data, please return it's value in <this> part of my fixed-format output data "
Now that the application is obvious, please note that I am aware of using other methods such as checking the value of "totalResults"
, in combination with HTTP 200
, amongst others, however:
jq
may be useful elsewhere and I'd like to address it as it. liveBroadcastContent
EDIT: Just to clarify - this isn't about the behavior of jq
across versions (something that would belong in the jq
forums) - It's about making the most robust portable code. I tend to think that versions >1.5 are simply forgiving a poorly formed expression (which I'm trying to work out here)
The reason your snippet fails in jq 1.4 is that foreach
was only introduced in version 1.5.
I'm not sure that your program with foreach
is consistent with your stated requirements, which unfortunately are slightly unclear. For example, what if the "liveBroadcastContent" key appears more than once in the input JSON entity?
Your stated requirements as I understand them (glossing over the ambiguity) would correspond to the following program, which has been tested with jq 1.4, 1.5 and the current "master" version:
(reduce (..| select(type == "object" and has("liveBroadcastContent"))) as $item
(false; $item | .liveBroadcastContent)) as $chanstatus
| {location:"location",
channel:"channelid",
current_id:"vId",
id_status:$chanstatus,
url:"https://youtu.be/\("vId")"}
For multiline programs such as this, it's usually much more convenient to use the -f option of jq, eg jq -f program.jq
If you need to accommodate jq 1.3 as well, then you'd have to handle ..
, which can be done by using dotdot
defined as follows:
def dotdot:
recurse(if (type | . == "object" or . == "array") then .[] else empty end);
I'm not sure what your input actually looks like, but given what you've shown here, it doesn't have to be that complicated.
{
location: "location",
channel: "channelid",
current_id: "vId",
id_status: (.liveBroadcastContent? // false),
url: "https://youtu.be/vId"
}
You wanted to get the value of liveBroadcastContent
if it exists, otherwise false
and that's what precisely .liveBroadcastContent? // false
.liveBroadcastContent? // false
does (assuming null
is not a valid value).
Seeing your full input object, it seems like a search result from a web api. I don't think using recursion here is really necessary. If the goal is take each of the results and display various information about each one, I would write this filter instead. (guessing at some of the fields)
.items[] | {
location: .channelTitle,
channel: .channelId,
current_id: .id,
id_status: (.liveBroadcastContent? // false),
url: "https://youtu.be/\(.id)"
}
If on the other hand, you were using the search results to determine whether a feed was available (based on your negative input case), I think it would be better to approach it finding the property on the list of results, rather than just the mere existence of the property anywhere.
I would do this instead:
{
location: "location",
channel: "channelid",
current_id: "vId",
id_status: ([.items[].snippet.liveBroadcastContent | select(. != null)][0] // false),
url: "https://youtu.be/vId"
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.