How to use regex to match a JSON value with jq? - json

My JSON data:
[
"delivery_1b36940ef75c49a8864d8cb3ea6a3a9f",
"toPayBtn_10021",
"item_fdd0772d0dd74dea93033761ca14e781",
"item_4f1a3f6fd3afdb940be008a0d325f9ad",
"delivery_d69dc5e9df971c9b2b1736c2231cb4a9",
"orderTotal_1",
"address_BILLING#1",
"delivery_185e36d98d5e4cc1808e59e44df8c71c",
"voucherInput_1",
"address_DELIVERY#1",
"item_864e1a7daf2aa424cbcb2251d55abda9",
"item_913196f953cbe8cfc2851c8fa9498607"
]
I want to match toPayBtn_10021 but the number after toPayBtn_ is dynamic, it can be toPayBtn_10 toPayBtn_2 toPayBtn_847 etc...
I have tried
jq '.toPayBtn_*'
but it doesn't work, how do I fix it ?

.[] | select( test("^toPayBtn_") )

Related

Get value if object or string if string in jq array

I have a JSON object that looks like this:
[{"name":"NAME_1"},"NAME_2"]
I would like an output of
["NAME_1", "NAME_2"]
Some of the entries in the array are an object with a key "name" and some are just a string of the name. I am trying to extract an array of the names. Using
jq -cr '.[].name // []'
throws an error as it is trying to index .name of the string object. Is there a way to check if it is a string, and if so just use its value instead of .name?
echo '[{"name":"NAME_1"},"NAME_2"]' \
| jq '[ .[] | if (.|type) == "object" then .name else . end ]'
[
"NAME_1"
"NAME_2"
]
Ref:
https://stedolan.github.io/jq/manual/#ConditionalsandComparisons
https://stedolan.github.io/jq/manual/#type
As #LĂ©aGris comments, a simpler version
jq '[ .[] | .name? // . ]' file
https://stedolan.github.io/jq/manual/#ErrorSuppression/OptionalOperator:%3f
https://stedolan.github.io/jq/manual/#Alternativeoperator://
You can use the type function which returns "object" for objects.
jq '.[] | if type == "object" then .name else . end' file.json
To get the output as array, just wrap the whole expression into [ ... ].
Just use the error suppression operator with ?, map and scalars
jq 'map( .name?, scalars )'
Note that by using scalars, it is assumed that other than objects with name, all others are names of form NAME_*. If there are other strings as well, and you need to exclude some of them you might need to add some additional logic to do that. e.g. using startswith(..) with a string of your choice.
map( .name?, select( scalars | startswith("NAME") ) )
Demo
With your shown samples only, please try following jq code. Using tostream function here to get the required values from requirement.
jq -c '[.[] | tostream | if .[1] != null then .[1] else empty end]' Input_file

Extract part of the string elements in an array using jq

I'm trying to extract part of the string in elements of an array, and create a new array with these extractions.
[
"local/binaries/app-2.21.0.tar.gz",
"local/binaries/app-2.20.0.tar.gz",
"local/binaries/app-2.19.1.tar.gz",
"local/binaries/app-2.19.0.tar.gz",
"local/binaries/app-2.18.0.tar.gz"
]
Desired output
[
"app-2.21.0",
"app-2.20.0",
"app-2.19.1",
"app-2.19.0",
"app-2.18.0"
]
You can use jq's capture function with regular expressions.
jq '[.[] | capture("(?<captured>app-[0-9]+\\.[0-9]+\\.[0-9]+)") | .[]]'
Try it out on jq playground.
Documentation: https://stedolan.github.io/jq/manual/#RegularexpressionsPCRE

Why doesn't fromjson work as a map function on an array of objects?

I'm trying to iterate through an object and convert any value (top level only for now, no recursion) that is a valid json string to json.
I think the answer lies in using the correct incantation perhaps something like with_entries(.value |= try fromjson), but I'm having trouble getting it working. So I broke it down a bit to try something simpler.
How about the following list of objects - I just want to parse the value key of each of them if it is a string that yields valid json (let's ignore the invalid cases for now, they can return null).
So I tried this:
$ jq -n '[{key: "one", value: 1},{key: "two", value: "{\"object\":true}"}] | map(.value |= try fromjson)'
[
{
"key": "one"
},
{
"key": "two"
}
]
Values are both missing even though the two key is a valid json string.
But if I try the same with a simple array, it works as expected:
$ jq -n '[1, "two", "{\"three\":3}"] | .[] | fromjson?'
{
"three": 3
}
So my question is what I am doing wrong here?
Thanks in advance for any pointers.
You have come across one of the (somewhat well-known) deficiencies of jq, namely that the trio of map, |=, try (and therefore postfix ?) do not mix well.
The good news is that the following will work in jq 1.5 and later:
map(.value = (.value | . as $v | try fromjson catch $v))
or equivalently:
map(.value as $v | .value = try ($v|fromjson) catch $v)

How to access the value of an unknown key?

I have the following JSON file
{
"https://test.com/gg": [
"msg",
"popup",
"url"
]
}
What I want to achieve is to parse the values to output the following
https://test.com/gg?msg=gg
https://test.com/gg?popup=gg
https://test.com/gg?url=gg
I'm assuming it can be done using jq but I'm not sure how.
The way i know is if the elemets were named like bellow:
{
"url":"https://test.com/gg": [
"p1":"msg",
]
}
I would pull the elements like:
cat json | jq "url.[p1]"
But in my case is it not named.
jq --raw-output 'to_entries[0] | .key as $url | .value[] | "\($url)?\(.)=gg"' <your json file here>
Where
to_entries[0] yields {"key":"https://test.com/gg","value":["msg","popup","url"]}
(Save .key as $url for later)
Then "emit" all values with .value[]
For each "emitted" value, produce the string "\($url)?\(.)=gg" where . is the current value

add values to array of keys with JQ

I have a simple JSON array:
[
"smoke-tests",
"other-tests"
]
I'd like to convert to a simple JSON:
{"smoke-tests": true,
"other-tests": true
}
I've tried several jq examples, but none seem to do what I want.
jq '.[] | walk(.key = true)' produces a compile error.
If you like the efficiency of reduce but don't want to use reduce explicitly:
. as $in | {} | .[$in[]] = true
$ s='["smoke-tests", "other-tests"]'
$ jq '[.[] | {(.): true}] | add' <<<"$s"
{
"smoke-tests": true,
"other-tests": true
}
Breaking down how that works: .[] | {(.): true} converts each item into a dictionary mapping the value (as a key) to true. Surrounding that in [ ] means we generate a list of such objects; sending that to add combines them into a single object.
Here is a solution using add. It's close to Charles's solution but uses the behavior of Object construction to implicitly return multiple objects when used with an expression which returns multiple results.
[{(.[]):true}]|add
With reduce() function:
jq 'reduce .[] as $k ({}; .[$k]=true)' file
The output:
{
"smoke-tests": true,
"other-tests": true
}