Jq getting output from nested hash - jq

Hi I am trying to parse below hash with jq
{
"name": "a",
"data": [
{
"sensitive": false,
"type": "string",
"value": "mykeypair"
},
{
"sensitive": false,
"type": "int",
"value": 123
}
]
}
and get output like
a,string,mykeypair
a,int,123
I am able to get output like this
a,string,mykeypair
a,int,mykeypair
a,string,123
a,int,123

jq solution:
jq -r '.name as $n | .data[] | [$n, .type, .value] | #csv' file.json
The output:
"a","string","mykeypair"
"a","int",123
If it's mandatory to output unquoted values:
jq -r '.name as $n | .data[] | [$n, .type, "\(.value)"] | join(",")' file.json
The output:
a,string,mykeypair
a,int,123

Related

Matching When Value Is List

I have an API dump file that is similar to this.
{
"abc": {
"Code": "ABC",
"Type": [] },
"def": {
"Code": "DEF",
"Type": [
"A"
]
},
"ghi": {
"Code": "GHI",
"Type": [
"B"
]
},
"jkl": {
"Code": "JKL",
"Type": [
"A",
"B"
]
},
"mno": {
"Code": "MNO",
"Type": [ "Universal" ]
}
}
I am trying to extract objects, and get Code keys based on certain Type matches.
For example.
Trying to where Type matches "A", "B", "A, B", or Universal, I am getting objects that contain both, or nothing in certain cases.
Here is what I tried.
jq -r '.[] | select(.Type[] == "A") | .Code' /tmp/test.json
I get
DEF JKL
Which is unexpectedly matching Type ["A"} and Type ["A", "B"]
jq -r '.[] | select(.Type[] == "B") | .Code' /tmp/test.json
I get.
GHI JKL
Which is unexpectedly matching Type ["B"} and Type ["A", "B"]
jq -r '.[] | select(.Type[] == "A, B") | .Code' /tmp/test.json
Matches nothing.
This works as expected.
jq -r '.[] | select(.Type[] == "Universal") | .Code' /tmp/test.json
MNO
If you wanted exact match, save following into script.jq :
.[] | select(.Type == $match) | .Code
Then test with
$ jq -r --argjson match '["A"]' -f script.jq test.json
DEF
$ jq -r --argjson match '["B"]' -f script.jq test.json
GHI
$ jq -r --argjson match '["A", "B"]' -f script.jq test.json
JKL
The jq program
.[] | select(any(.Type[]; IN("A","B","A, B","Universal"))) | .Code
produces:
"DEF"
"GHI"
"JKL"
"MNO"

jq - Get objects with latest date

Json looks like this:
cat test.json |jq -r ".nodes[].run_data"
{
"id": "1234",
"status": "PASSED",
"penultimate_status": "PASSED",
"end_time":"2022-02-28T09:50:05Z"
}
{
"id": "4321",
"status": "PASSED",
"penultimate_status": "UNKNOWN",
"end_time": "2020-10-14T13:52:57Z"
}
I want to get "status" and "end_time" of the newest run. Unfortunately the order is not fix. Meaning the newest run can be first in the list, but also last or in the middle...
Use sort_by to bring the items in order, then extract the last item:
jq '
[.nodes[].run_data]
| sort_by(.end_time) | last
| {status, end_time}
' test.json
{
"status": "PASSED",
"end_time": "2022-02-28T09:50:05Z"
}
To get the fields in another format, replace {status, end_time} with your format, e.g. "\(.end_time): Status \(.status)", and set the -r flag as this isn't JSON anymore but raw text.
You can use transpose to map each object with its end_time.
Here I have converted end_time to seconds since Unix epoch and outputted the object with largest seconds value (this is the newest).
[
[. | map(.end_time | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime), [.[0], .[1]]]
| transpose[]
| .[1] += {secs: .[0]} | .[1]
]
| sort_by(.secs) | last
| {status, end_time}
Output
{
"status": "PASSED",
"end_time": "2022-02-28T09:50:05Z"
}
Demo
https://jqplay.org/s/w1z2n2drc7

jq: list users belonging to a specific group in array

input json:
[
{
"user": "u1"
},
{
"user": "u2",
"groups": [
{
"id": "100001",
"name": "G1"
},
{
"id": "100002",
"name": "G2"
}
]
},
{
"user": "u3",
"groups": [
{
"id": "100001",
"name": "G1"
}
]
}
]
I want to find all users belonging to specific group (searching by group name or group id in the groups array)
$ jq -r '.[]|select(.groups[].name=="G1" | .user)' json
jq: error (at json:27): Cannot iterate over null (null)
Desired output format when searching of example group G1 would be:
u2
u3
Additional question:
Is it possible to produce comma-separated output u2,u3 without using external utilities like tr?
Better enter your serach data from parameters using --arg and use any to avoid duplicate outputs if both inputs match:
jq -r --arg id "" --arg name "G1" '
.[] | select(.groups | map(.id == $id or .name == $name) | any)? | .user
'
u2
u3
Demo
Using ? as the Optional Object Identifier-Index operator, you could do a select as below
map(select(.groups[].name == "G1")? | .user)
and un-wrap the results from the array by using [] at the end of the filter. To combine multiple selection conditions use the boolean operators with and/or inside the select statement
See demo on jqplay

Extract nested properties from an array of objects

I have the following JSON file :
{
"filter": [
{
"id": "id_1",
"criteria": {
"from": "mail#domain1.com",
"subject": "subject_1"
},
"action": {
"addLabelIds": [
"Label_id_1"
],
"removeLabelIds": [
"INBOX",
"SPAM"
]
}
},
{
"id": "id_2",
"criteria": {
"from": "mail#domain2.com",
"subject": "subject_1"
},
"action": {
"addLabelIds": [
"Label_id_2"
],
"removeLabelIds": [
"INBOX",
"SPAM"
]
}
}
]
}
And I would like to extract emails values : mail#domain1.com and mail#domain2.com
I have tried this command:
jq --raw-output '.filter[] | select(.criteria.from | test("mail"; "i")) | .id'
But does not work, I get this error :
jq: error (at <stdin>:1206): null (null) cannot be matched, as it is
not a string exit status 5
Another point : how to display the value of "id" key, where "from" key value = mail#domain1.com ?
So in my file id = id_1
Do you have an idea ?
If you only need to extract the emails from .criteria.from then this filter is enough as far as I can tell:
jq --raw-output '.filter[].criteria.from' file.json
If some objects don't have a criteria object then you can filter out nulls with:
jq --raw-output '.filter[].criteria.from | select(. != null)' file.json
If you want to keep the emails equal to "mail#domain1.com":
jq --raw-output '.filter[].criteria.from | select(. == "mail#domain1.com")' file.json
If you want to keep the emails that start with "mail#":
jq --raw-output '.filter[].criteria.from | select(. != null) | select(startswith("mail#"))' file.json
I would like to extract emails values
There is a wide spectrum of possible answers, with these
amongst the least specific with respect to where in the JSON the email addresses occur:
.. | objects | .from | select(type=="string")
.. | strings | select(test("#([a-z0-9]+[.])+[a-z]+$"))

Remove slash character in JSON response using jq

Docker Engine API returns container name with / appended
{
"Id": "8dfafdbc3a40",
"Names": [
"/boring_feynman"
],
"Image": "ubuntu:latest",
"ImageID": "d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82",
"Command": "echo 1",
"Created": 1367854155,
"State": "Exited",
"Status": "Exit 0",
"Ports": [{
"PrivatePort": 2222,
"PublicPort": 3333,
"Type": "tcp"
}],
"Labels": {
"com.example.vendor": "Acme",
"com.example.license": "GPL",
"com.example.version": "1.0"
},
"SizeRw": 12288,
"SizeRootFs": 0,
"HostConfig": {
"NetworkMode": "default"
},
"NetworkSettings": {
"Networks": {}
},
"Mounts": [{
"Name": "fac362...80535",
"Source": "/data",
"Destination": "/data",
"Driver": "local",
"Mode": "ro,Z",
"RW": false,
"Propagation": ""
}]
}
I want to remove the slash so the response can be used as a table in JQ:
jq -r '(["Names","Image"] | (., map(length*"-"))), (.[] | [.Names, .Image]) | #tsv'
Currently, when I run the above, I get:
jq: error (at <stdin>:1): array (["/boring_feynman"]) is not valid in a csv row
The problem is not because of / in the .Names field, but in your expression. For filters like #csv or #tsv to work, the values need to be in a scalar format and in an array. But your expression .Name in of type array.
So basically you are passing this result to the #tsv function
[
[
"/boring_feynman"
],
"ubuntu:latest"
]
instead of
[
"/boring_feynman",
"ubuntu:latest"
]
So modifying your filter, you can do below for the JSON in question.
jq -r '(["Names","Image"] | (., map(length*"-"))), ([.Names[], .Image]) | #tsv'
or if you still want to remove the /, use gsub() function
jq -r '(["Names","Image"] | (., map(length*"-"))), ([ (.Names[] | gsub("^/";"")), .Image]) | #tsv'

Resources