jq json parser concate nested array object value - json

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)"

Related

iterate on key to get the contents of the key

IF I have json that looks like
{
"items": [
{
"name": "issue1",
"spec": {
"config": {
"setting1": abc,
"setting2": {
"name": "xyz"
}
},
"files": {
"name": "cde",
"path": "/home"
},
"program": {
"name": "apache"
}
}
}
]
}
and I want to have iteration at .items[0].spec where the key config,files,program's contents can be shown.. something like
config:
{
"setting1": abc,
"setting2": {
"name": "xyz"
}
}
files:
{
"name": "cde",
"path": "/home"
}
program:
{
"name": "apache"
}
and there might be things more or less than config/files/programs for each items.
I know that I can get the list of keys by jq -r '.items[0].spec| to_entries[].key' but not sure about formating the output and getting the contents of .items[].spec.xxxxx like above.
I also got very close by jq -r '{test: .items[0].spec | with_entries(select(.value != null)) }' but I want to seperate each item per key
Also this got me even closer! but how do you get the json syntax of the object to display uncompressed?
jq -r '.items[].spec | keys[] as $k | "\($k):\n \(.[$k])"'
The "," operator is the magic ingredient you seem to be looking for:
.items[].spec | keys[] as $k | $k, .[$k]

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)

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

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.

Creating a new element in an json object using jq

Is there a way to create a new element in an existing json object using jq? Example below:
Let's say I have this json object and would like to add a new element to foo:
json='{
"id": "<id>>",
"name": "<name>",
"properties": {
"State": "<state>",
"requests": [],
"foo": [
{
"id": "<id1>",
"bar1": [
{
"baz1": "*"
}
]
},
{
"id": "<id2>",
"bar2": [
{
"baz2": "*"
}
]
}
]
}
}'
This command works to do that:
json2=$($json1 | jq '.properties.foo += [ { "id": "<id3>", "bar3": [ { "baz3": "*"} ] } ]')
However, running that same command without a preexisting foo element fails (example array below):
json3='{
"id": "<id>>",
"name": "<name>",
"properties": {
"State": "<state>",
"requests": []
}
}'
Is there a way in jq to create that element in the json object if one already does not exist?
Thanks!
There is nothing wrong with your jq program, which can be seen by running:
jq '.properties.foo += [ { "id": "<id3>", "bar3": [ { "baz3": "*"} ] } ]' <<< "$json3"
It looks like the problem is with your invocation but since it's not clear what $json1 is, I'll just guess that the above is sufficient for you to resolve the issue.

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