Matching When Value Is List - jq

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"

Related

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]+$"))

Jq getting output from nested hash

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

jq query with condition and format output/labels

I have a JSON file:
[
{
"platform": "p1",
"id": "5",
"pri": "0",
"sec": "20"
}
]
[
{
"platform": "p2",
"id": "6",
"pri": "10",
"sec": "0"
}
]
I can to format it to the form:
$ jq -c '.[]|{PLATFORM: .platform, ID: .id, PRI: .pri, SEC: .sec}' test.json
{"PLATFORM":"p1","ID":"5","PRI":"0","SEC":"20"}
{"PLATFORM":"p2","ID":"6","PRI":"10","SEC":"0"}
$
but how to ignore SEC/PRI with "0" and get output in form:
PLATFORM:p1, ID:5, SEC:20
PLATFORM:p2, ID:6, PRI:10
I can process it with bash/awk command, but maybe someone have a solution with jq directly.
thank you,
You can use conditional statements to remove the unwanted keys, e.g.:
if (.sec == "0") then del(.sec) else . end
The formatting could be done with #tsv by converting the data to an array, e.g.:
filter.jq
.[] |
if (.sec == "0") then del(.sec) else . end |
if (.pri == "0") then del(.pri) else . end |
to_entries |
map("\(.key | ascii_upcase):\(.value)") |
#tsv
Run it like this:
jq -crf filter.jq test.json
Output:
PLATFORM:p1 ID:5 SEC:20
PLATFORM:p2 ID:6 PRI:10
jq solution:
jq -c 'def del_empty($k): if (.[$k]|tonumber > 0) then . else del(.[$k]) end;
.[] | {PLATFORM: .platform, ID: .id, PRI: .pri, SEC: .sec}
| del_empty("PRI")
| del_empty("SEC")' test.json
The output:
{"PLATFORM":"p1","ID":"5","SEC":"20"}
{"PLATFORM":"p2","ID":"6","PRI":"10"}

Combine the value from a key with all array entries

I have json input as follows:
[{
"a": "123",
"b": [
"xyz",
"uvw"
]
}, {
"a": "456",
"b": [
"ghi"
]
}]
and I'd like to produce a list where each object's "a" is combined with each element of "b" using a delimiter. Is this possible to do using jq?
123|xyz
123|uvw
456|ghi
You can change the delimiter on the fly if you parameterize it.
$ jq -r --arg delim '|' '.[] | "\(.a)\($delim)\(.b[])"' input.json

Resources