jq pipe operator in nested array - jq

Using code below to pull data from a local json file.
The file is very large and is nested with objects and arrays. There are multiple objects in the .ratings[] that I would like to extract.
How can I use the pipe operator in the .ratings[] array so that I don't have to retype .ratings[] for each piece of data that I would like to pull?
jq -r '.players[] | [.firstName,.lastName,.tid,.pid,.ratings[].spd,.ratings[].jmp] | join(", ")'

You can enclose it in () to use the pipe sign:
.players[] | [.firstName, .lastName, .tid, .pid, (.ratings[] | .spd, .jmp)] | join(", ")
Try it online

You didn't specify the expected output, so it is not clear if your proposed solution gives you the output you want.
Given the following input:
{
"players": [
{
"firstName": "fname1",
"lastName": "lname1",
"tid": "tid1",
"pid": "pid1",
"ratings": [
{
"spd": "spd1-1",
"jmp": "jmp1-1"
}
]
},
{
"firstName": "fname2",
"lastName": "lname2",
"tid": "tid2",
"pid": "pid2",
"ratings": [
{
"spd": "spd2-1",
"jmp": "jmp2-1"
},
{
"spd": "spd2-2",
"jmp": "jmp2-2"
}
]
},
{
"firstName": "fname3",
"lastName": "lname3",
"tid": "tid3",
"pid": "pid3",
"ratings": [
{
"spd": "spd3-1",
"jmp": "jmp3-2"
},
{
"spd": "spd3-2",
"jmp": "jmp3-2"
},
{
"spd": "spd3-3",
"jmp": "jmp3-3"
}
]
}
]
}
Your solution and the answer from 0ston0 will give you 1 line per player, but a different number of columns per line:
.players[] | [.firstName,.lastName,.tid,.pid,(.ratings[]|.spd,.jmp)] | join(", ")
generates:
fname1, lname1, tid1, pid1, spd1-1, jmp1-1
fname2, lname2, tid2, pid2, spd2-1, jmp2-1, spd2-2, jmp2-2
fname3, lname3, tid3, pid3, spd3-1, jmp3-2, spd3-2, jmp3-2, spd3-3, jmp3-3
This might or might not be what want your result to look like.
A different solution will print one line per rating, but duplicate the players' names. Running:
.players[] | [.firstName,.lastName,.tid,.pid] + (.ratings[]|[.spd,.jmp]) | join(", ")
will result in:
fname1, lname1, tid1, pid1, spd1-1, jmp1-1
fname2, lname2, tid2, pid2, spd2-1, jmp2-1
fname2, lname2, tid2, pid2, spd2-2, jmp2-2
fname3, lname3, tid3, pid3, spd3-1, jmp3-2
fname3, lname3, tid3, pid3, spd3-2, jmp3-2
fname3, lname3, tid3, pid3, spd3-3, jmp3-3
Both solutions are valid for different use cases and depending on how you are going to subsequently process the data.

Related

Parse an array of json object using jq

I am trying to parse the below json file and store the result into another json file. How do I achieve this ?
{
"Objects": [
{
"ElementName": "Test1",
"ElementArray": ["abc","bcd"],
"ElementUnit": "4"
},
{
"ElementName": "Test2",
"ElementArray": ["abc","bcde"],
"ElementUnit": "8"
}
]
}
Expected result :
{
"Test1" :[
"abc","bcd"
],
"Test2" :[
"abc","bcde"
]
}
I've tried something on the lines of the below but I seem to be off -
jq '[.Objects[].ElementName ,(.Objects[]. ElementArray[])]' user1.json
jq ".Objects[].ElementName .Objects[].ElementArray" ruser1.json
Your expected output needs to be wrapped in curly braces in order to be a valid JSON object. That said, use from_entries to create an object from an array of key-value pairs, which can be produced by accordingly mapping the input object's Objects array.
.Objects | map({key: .ElementName, value: .ElementArray}) | from_entries
{
"Test1": [
"abc",
"bcd"
],
"Test2": [
"abc",
"bcde"
]
}
Demo
Demo
https://jqplay.org/s/YbjICOd8EJ
You can also use reduce
reduce .Objects[] as $o ({}; .[$o.ElementName]=$o.ElementArray)

list each specific element with parent name

I have json with random elements on array:
[
{
"system": {
"name": "sys1",
"interfaces": [
{
"ip": "1.1.1.1",
"ent": "ent1"
},
{
"ip": "2.2.2.2",
"ent": "ent0"
}
]
}
},
{
"system": {
"name": "sys2",
"interfaces": [
{
"ip": "3.3.3.3",
"ent": "ent0"
}
]
}
},
{
"system": {
"name": "sys3",
"interfaces": null
}
},
{
"system": {
"name": "sys4"
}
}
]
I need get following output with jq:
sys1 1.1.1.1 ent1
sys1 2.2.2.2 ent0
sys2 3.3.3.3 ent0
I tried following filter:
$ jq -r '.[]|[.system.name, .system.interfaces[].ip, .system.interfaces[].ent]|#tsv' test_json2
sys1 1.1.1.1 2.2.2.2 ent1 ent0
sys2 3.3.3.3 ent0
How to split line 1 to achieve expected result?
Update: I met new case when array is null and I get now following error using filrer from pmf's answer:
jq: error (at test_json2:34): Cannot iterate over null (null)
Iterate outside the array which contains the .name. That way, another array is generated for each iteration step.
jq -r '.[].system | [.name] + (.interfaces[]? | [.[]]) | #tsv' test_json2
Demo
If the objects in the .interfaces array can have more than just those two field, but you only want to output said two fields, name them explicitly.
jq -r '.[].system | [.name] + (.interfaces[]? | [.ip, .ent]) | #tsv' test_json2
Demo
Output is:
sys1 1.1.1.1 ent1
sys1 2.2.2.2 ent0
sys2 3.3.3.3 ent0
You can use array to group each interface.
.[] | .system | select(.name=="sys1" or .name=="sys2") | [.name] + (.interfaces[] | [.[]]) | #tsv
Demo
https://jqplay.org/s/iucSZqkB1r
Note that .[] on an object returns its values.

Extract the jq record only when match the first and last name

I can get the first and birthday,
{
"users": [
{
"first": "Stevie",
"last": "Wonder",
"birthday": "01/01/1945"
},
{
"first": "Michael",
"last": "Jackson",
"birthday": "03/23/1963"
}
]
}
So with this jq command, I can get the record:
$ cat a.json |jq '.users[] | .first + " " + .last + " " + .birthday'
"Stevie Wonder 01/01/1945"
"Michael Jackson 03/23/1963"
And I am close to the answer to match the first name
$ cat a.json |jq '.users[] | select(.first=="Stevie") | .birthday '
"01/01/1945"
But how to get the output which matched both first and last name?
Here is an approach which starts by filtering out .users which do not meet your criteria:
.users |= map(select(
(.first == "Stevie") and (.last == "Wonder")
))
if you Try it online! you will observe it simplifies your data to just
{
"users": [
{
"first": "Stevie",
"last": "Wonder",
"birthday": "01/01/1945"
}
]
}
Then you can add more filters if you want particular elements (e.g. .birthday):
.users |= map(select(
(.first == "Stevie") and (.last == "Wonder")
))
| .users[].birthday
to obtain
Try it online!
"01/01/1945"
This may seem needlessly redundant but may be easier if you are experimenting without precise requirements.

jq syntax help for querying lists output

I need help in correcting jq test cases syntax. Following is output file & trying to test ID list with command below. Gives error index to string type.
[[ $(echo $output| jq -r '.output.value[] | select(.identity).id_list') == *"id2"* ]]
output = {
"resource_output": {
"value": {
"identity": [
{
"id_list": [
"/subscriptions/---/id1",
"/subscriptions/---/id2",
"/subscriptions/--/id3"
],
"principal_id": "",
"tenant_id": "",
"type": "managed"
}
]
}
}
Your query does not match the sample JSON, and you have not indicated what output you are expecting, but the following variation of your query illustrates how to use select and test with your data along the lines suggested by your attempt:
echo "$output" |
jq -r '.resource_output.identity[].id_list[] | select(test("id2"))'
Output:
/subscriptions/---/id2

jq: pass variable argument to be used as filter [duplicate]

This question already has answers here:
jq: pass string argument without quotes
(3 answers)
Closed 4 years ago.
How do I pass a variable argument to JQ program that will be used as a filter. Since by default --arg passes the argument as a a string wrapped with quotes the same cannot be used to apply a filter.
here is the JQ program that finds a particular path in the given json and adds a static key value to that path but doesn't work because of the quotes issue.
--argjson name '{ "pattern": "XYZ"}' 'def p: "." + (paths | select(.[-1] == "p-enum") | .[0:-1] | join(".")) ; .|p += $name' sample.json
here is the sample json
{
"type": "object",
"description": "Contains information.",
"properties": {
"type": {
"description": "Type.",
"type": "string",
"p-enum": [
{
"value": "IND",
"description": "Ind."
},
{
"value": "PROP",
"description": "Prop."
}
]
}
}
}
Based on how I interpreted how you were using jq in your other question, it depends on how complicated your filter will be. Any argument that is to be interpreted by jq is not the way you should approach it. This is the equivalent of using eval() and is not only unsupported, but just not a good way to approach this.
If you're simply accessing a property of the input, you have a couple of ways using simple indexing or using getpath/1 for nested paths.
# indexing
# { "properties": ... }
$ jq --arg p 'properties' '.[$p]' input.json
# using getpath
# { "foo": { "bar": ... } }
$ jq --argjson path '["foo","bar"]' 'getpath($path)' input.json

Resources