JQ reshape nested array - json

I have an issue with jq and nested arrays, I cannot get why it is creating multiple objects:
echo '{
"first": [
{
"second": {
"id": 1,
"third": [
{
"value": "aa"
},
{
"value": "bb"
}
]
}
}
]
}' | jq '.first[].second | {id: .id, prop: .third[].value}'
This is returning:
{
"id": 1,
"prop": "aa"
}
{
"id": 1,
"prop": "bb"
}
But I would like to have:
{
"id": 1,
"prop": ["aa", "bb"]
}
What am I missing?

Use the map builtin to transform the array into just .values:
jq '.first[].second | {id: .id, prop: .third | map(.value)}'
{
"id": 1,
"prop": [
"aa",
"bb"
]
}
Demo

You need to put values in an array :
jq '.first[].second | {id: .id, prop: [.third[].value]}'

Related

How to select items in JQ based on values in array

I have a json file with data like this:
{
"data": {
"all": {
"members": [
{
"id": 10,
"name": "First"
},
{
"id": 12,
"name": "Second"
},
{
"id": 14,
"name": "Third"
}
],
"live": {
"online": [
10,
14
]
}
}
}
}
How can I use jq to select and show only the JSON values in data.all.members that have their id in data.all.live.online array?
So the output would be something like:
{
"members": [
{
"id": 10,
"name": "First"
},
{
"id": 14,
"name": "Third"
}
]
}
One way:
jq '.data.all
| .live.online as $online
| {members}
| .members |= map( select(.id | IN($online[]) // null) )
' data.json
Here's a solution that should be fairly easy to understand:
.data.all
| .live.online as $online
| { members: .members | map(select([.id] | inside($online))) }
Output:
{
"members": [
{
"id": 10,
"name": "First"
},
{
"id": 14,
"name": "Third"
}
]
}
And if you need more flexibility how your ids are matched:
.data.all
| .live.online as $online
| { members: .members | map(select(.id as $id | $online | any(. == $id))) }

jq ~ collapse specific single object arrays?

corresponding to jq ~ is there a better way to collapse single object arrays? and R: Nested data.table to JSON
how do I collapse only specific elements?
I want to get rid of the "group" arrays in
[
{
"id2": "A",
"group": [
{
"data": [
{
"id1": 1,
"group": [
{
"data": [
{
"a": 1,
"b": 1
},
{
"a": 2,
"b": 2
}
],
"type": "test"
}
],
"type": "B"
}
],
"type": "C"
}
]
},
{
"id2": "C",
"group": [
{
"data": [
{
"id1": 3,
"group": [
{
"data": [
{
"a": 1,
"b": 1
}
],
"type": "test"
}
],
"type": "B"
}
],
"type": "C"
}
]
}
]
desired output
[{
"id2": "A",
"group": {
"data": [{
"id1": 1,
"group": {
"data": [{
"a": 1,
"b": 1
},
{
"a": 2,
"b": 2
}
],
"type": "test"
},
"type": "B"
}],
"type": "C"
}
},
{
"id2": "C",
"group": {
"data": [{
"id1": 3,
"group": {
"data": [{
"a": 1,
"b": 1
}],
"type": "test"
},
"type": "B"
}],
"type": "C"
}
}
]
The line 'walk(if type=="array" and length==1 then .[0] else . end)' additionally removes the array from the single "data" object.
Unfortunately, we are not able to install the jq 1.6 version on our RStudio Server und thereby I'm not able to use the walk function. (Although is working perfectly fine on my local system)
Can anybody help me out with an alternative solution without walk? Would be highly appreciated.
edit
Ok I got it. I can manually add the walk function such as:
'def walk(f):
. as $in
| if type == "object" then
reduce keys_unsorted[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end; walk(if type=="object"
and has("group")
and (.group | type)=="array"
and (.group | length)==1
then .group = .group[0]
else . end)'
We could operate one level higher in the nesting hierarchy, and test for "group" being a key, then update accordingly .group = .group[0] instead of . = .[0]
jq 'walk(if type=="object"
and has("group")
and (.group | type)=="array"
and (.group | length)==1
then .group = .group[0]
else . end)'

How to filter an list by the value of an inner dict with jq?

Giving the input JSON:
[
{
"name": "foo",
"value": 1
},
{
"name": "bar",
"value": 1
},
{
"name": "foo",
"value": 2
}
]
I'm trying to get the dicts with the name foo, so the expecting output is:
{
"name": "foo",
"value": 1
},
{
"name": "foo",
"value": 2
}
Try this
jq '.[] | select(.name == "foo")'
Demo

jq sort using the value of a nested array element

I need some help using jq to sort an array of elements where each element contains a nested
tags array of elements. My input JSON looks like this:
{
"result": [
{
"name": "ct-1",
"tags": [
{
"key": "service_name",
"value": "BaseCT"
},
{
"key": "sequence",
"value": "bb"
}
]
},
{
"name": "ct-2",
"tags": [
{
"key": "service_name",
"value": "BaseCT"
},
{
"key": "sequence",
"value": "aa"
}
]
}
]
}
I would like to sort using the value of the sequence tag in the nested tags array so that the output looks like this:
{
"result": [
{
"name": "ct-2",
"tags": [
{
"key": "service_name",
"value": "BaseCT"
},
{
"key": "sequence",
"value": "aa"
}
]
},
{
"name": "ct-1",
"tags": [
{
"key": "service_name",
"value": "BaseCT"
},
{
"key": "sequence",
"value": "bb"
}
]
}
]
}
I have tried the following jq command:
$ jq '.result |= ([.[] | .tags[] | select(.key == "sequence") | .value] | sort_by(.))' input.json
but I get the following result:
{
"result": [
"aa",
"bb"
]
}
Please let me know if you know how to deal with this scenario.
from_entries converts an array of key-value pairs to an object, you can use it with sort_by like this:
.result |= sort_by(.tags | from_entries | .sequence)

jq select objects that have specific value in nested json bash

this is my json.
[
{
"time": "2017-06-10 00:00:48-0400,317",
"UserInfo": {
"AppId": "ONE_SEARCH",
"UsageGroupId": "92600",
},
"Items": [
{
"PublicationCode": "",
"OpenUrlRefId": "",
"ReferringUrl": "N",
"OpenAccess": "0",
"ItmId": "1328515516"
}
]
},
{
"time": "2017-06-10 00:00:48-0400,548",
"UserInfo": {
"AppId": "DIALOG",
"UsageGroupId": "1195735",
},
"Items": [
{
"Origin": "Alert",
"PublicationCode": "",
"NumberOfCopies": 1,
"ItmId": "1907446549"
},
{
"Origin": "Alert",
"PublicationCode": "",
"NumberOfCopies": 1,
"ItmId": "1907446950",
}
]
}
]
I want use jq to extract the object that have "Origin": "Alert" in its element "Items". And the result should looks like this:
{
"time": "2017-06-10 00:00:48-0400,548",
"UserInfo": {
"AppId": "DIALOG",
"UsageGroupId": "1195735",
},
"Items": [
{
"Origin": "Alert",
"PublicationCode": "",
"NumberOfCopies": 1,
"ItmId": "1907446549"
},
{
"Origin": "Alert",
"PublicationCode": "",
"NumberOfCopies": 1,
"ItmId": "1907446950",
}
]
}
Or this:
{
"Items": [
{
"Origin": "Alert",
"PublicationCode": "",
"NumberOfCopies": 1,
"ItmId": "1907446549",
"ReasonCode": ""
},
{
"Origin": "Alert",
"PublicationCode": "",
"NumberOfCopies": 1,
"ItmId": "1907446950",
}
]
}
How to do it by using jq? I have tried several ways but most of them will just return an array with all children objects that include "Origin":"Alert". I need these children objects still keep there structure, because I need to know which of them happened together and which of them happened separately.
BTW, the only value of "Origin" is "Alert". So if you have any method to select an object with a given key name, it should also work.
Thank you! :)
The filter:
.[] | select( any(.Items[]; .Origin == "Alert"))
produces the first-mentioned admissible result. If your jq does not have any/2 then I'd suggest upgrading. If that's not an option, then you could use the following simple but rather inefficient filter instead:
.[] | select( .Items | map(.Origin) | index("Alert"))
Or:
.[] | select(reduce .Items[] as $item (false; . or ($item | .Origin == "Alert")))