How can I print multiple values in one line by `jq`? - json

I have json data like below:
{
"Items": [
{
"id": {
"S": "c921e4eb-5958-424a-ae3a-b9cada0d9481"
},
"type": {
"S": "transaction.1612878877726"
}
},
{
"id": {
"S": "355057f0-4327-49c7-979f-5a27410d81ba"
},
"type": {
"S": "transaction.1612345630260"
}
},
{
"id": {
"S": "664dc02f-0ad8-484a-98a5-a403beea775b"
},
"type": {
"S": "transaction.1612164919232"
}
},
...
]
}
I'd like to print the value id and type in one line per item from the Items array, e.g.
c921e4eb-5958-424a-ae3a-b9cada0d9481, transaction.1612878877726
355057f0-4327-49c7-979f-5a27410d81ba, transaction.1612345630260
...
I tried cat file | jq '.Items[].id.S, .Items[].type.S' but it prints id and type in separate lines. How can I achieve it with jq?

I would just use string manipulation, either adding 3 strings :
jq --raw-output '.Items[] | .id.S + ", " + .type.S' file
or using string interpolation :
jq --raw-output '.Items[] | "\(.id.S), \(.type.S)"' file
You can try it here.

Related

Combining all key value pairs in one using jq filter or jq play

I want to transform JSON data using jq filter
Json data:
{
"main": [
{
"firstKey": "ABCD",
"id": "12345",
"data": [
{
"name": "first_id",
"value": "first_id_value"
},
{
"name": "second_id",
"value": "second_id_value"
},
{
"name": "third_id",
"value": "third_id_value"
}
]
}
]
}
Expected OUTPUT:
{
"firstKey": "ABCD",
"id": "12345",
"data.name.first_id": "first_id_value",
"data.name.second_id": "second_id_value",
"data.name.third_id": "third_id_value"
}
After many trials and errors, I was near to expected output using following filter expression
[.main[]|{"firstKey", "id"},foreach .data[] as $item (0; "data.name.\($item.name)" as $a|$item.value as $b| {($a): $b})][]
Used foreach as objects under "data" are dynamic. the number of objects can differ.
The output for the above expression is:
{
"firstKey": "ABCD",
"id": "12345"
}
{
"data.name.first_id": "first_id_value"
}
{
"data.name.second_id": "second_id_value"
}
{
"data.name.third_id": "third_id_value"
}
But I want the objects of data to be under the same braces as 'firstKey' and 'id'.
LINK to JqPlay
Any suggestions will be helpful.
Since your structure is so rigid, you can cheat and use the built-in from_entries, which takes a list of {key, value} pairs and constructs an object:
.main[] |
{firstKey, id} +
(.data | map({key: "data.name.\(.name)", value}) |
from_entries)

Create new JSON value out of strings extracted from another

I have a json file with the following input
{
"Arg":"room=Rhasspy rhasspyName",
"Results": [
{
"Name":"TV",
"Internals": { },
"Readings": { },
"Attributes": { "rhasspyName": "TV" }
},
{
"Name":"dyTest01",
"Internals": { },
"Readings": { },
"Attributes": { "rhasspyName": "radio" }
},
{
"Name":"enoAcPC01",
"Internals": { },
"Readings": { },
"Attributes": { "rhasspyName": "pc" }
} ],
"totalResultsReturned":3
}
With jq '.Results | .[] | .["Attributes"] | .rhasspyName' -r I can get a list like
TV
radio
pc
How can I take this input and create a new json looking like
{"Devices":["TV","radio","pc"]}
Put them into an array and pair that with Devices key in an object.
$ jq '{Devices:[.Results[].Attributes.rhasspyName]}' file
{
"Devices": [
"TV",
"radio",
"pc"
]
}
To create a new file with that JSON value, redirect JQ's stdout to a file, like:
jq '{Devices:[.Results[].Attributes.rhasspyName]}' file > newfile

How to delete array elements that end with 1?

I need to remove all array elements that have the name field ending with 1.
Input:
{
"foo": "bar",
"data": {
"code": "abc123",
"items": [
{
"name": "exp1"
},
{
"name": "exp2"
},
{
"name": "exp11"
}
]
}
}
Desired output:
{
"foo": "bar",
"data": {
"code": "abc123",
"items": [
{
"name": "exp2"
}
]
}
}
My attempt:
jq 'del(.data.items[] | select(.name | endswith("1")))' input
Which results in Invalid path expression.
You can use this jq filter:
jq '.data.items|=map(select(.name|endswith("1")|not))' file
This replace .data.items with the a new array having objects whose names don't end with 1.
Your attempt will work with recent versions of jq (that is, more recent than version 1.5).
Yet another variant (perhaps the most concise robust alternative):
.data.items|=map(select(.name|test("[^1]$")))

How can you sort a JSON object efficiently using JQ

I've got JSON in the format
{
"a": {
"size":3
},
"b": {
"size":2
},
"c": {
"size":1
}
}
I need to sort it by size, e.g.:
{
"c": {
"size": 1
},
"b": {
"size": 2
},
"a": {
"size": 3
}
}
I have found a way to do it, e.g.:
. as $in | keys_unsorted | map ({"key": ., "size" : $in[.].size}) | sort_by(.size) | map(.key | {(.) : $in[.]}) | add
but this seems quite complex so I'm hoping there's a simpler way that I've overlooked?
You can use to_entries / from_entries, like this:
jq 'to_entries|sort_by(.value.size)|from_entries' file.json
to_entries will transform your input object into a list of key/value pair objects:
[
{
"key": "a",
"value": {
"size": 3
}
},
...
{
"key": "c",
"value": {
"size": 1
}
}
]
That allows to apply sort_by(.value.size) to that list and then convert it back to an object using from_entries.

jq json parser concate nested array object value

Hi I have the below JSON file with nested object:
{
"Maps": {
"Campus": [
{
"name": "nus",
"Building": [
{
"name": "sde1",
"Floor": [
{
"name": "floor1"
},
{
"name": "floor2"
}
]
},
{
"name": "sde2"
}
]
},
{
"name": "ntu",
"Building": [
{
"name": "ece1",
"Floor": [
{
"name": "floor1"
},
{
"name": "floor2"
}
]
},
{
"name": "ece2"
}
]
}
]
}
}
I want to use jq to parse the above JSON file and get the below format:
nus>sde1>floor1
nus>sde1>floor2
ntu>ece1>floor1
ntu>ece1>floor2
basically I have to concatenate the Campus Name with Building Name and Floor name and put a < symbol in between.
If the nested object field Floor is not exist, ignore the parse and continue the next child object.
How to achieve that? thanks.
You can use the following jq command:
jq '.Maps.Campus[]|"\(.name)>\(.Building[]|"\(.name)>\(.Floor[]?.name)")"' file.json
jq is smart enough to print the combinations of .name and .Building[].name since .Building is an array. The same action get's applied to .Building[].name and Floor[]?.name. ? because floor is not always set.
Here is a solution which uses jq variables
.Maps.Campus[]
| .name as $campus
| .Building[]
| .name as $bldg
| .Floor[]?
| .name as $floor
| "\($campus)>\($bldg)>\($floor)"