Taking a json file as input such as:
{"computers":
[{"host":"example",
"platform":"some_platform",
"status":
{"working":"yes",
"display":["no"]},
"description":""
}]
}
...how can this be flattened to this form:
{"computers":
"host":"example",
"platform":"some_platform",
"working":"yes",
"display":"no",
"description":""
}
ie. the status element has been flattened, the square brackets in "display":["no"]
have been removed, and the square brackets around "computers":[...]
have been removed.
I have so far tried using flatten in multiple ways, eg.:
cat ./output.json | jq '.computers|.[]|.status|flatten'
but this only outputs the flattened version of the contents of the status element. I cannot work out how to replace the contents with the flattened version.
CodePudding user response:
If you're sure the computers
array will just contain a single object, you could use:
.computers |= (first | . .status | del(.status) | (.display |= join(.)))
That will alter the value of .computers
by doing to following:
- Get the
first
object - Move everything inside
.status
to the object itself del()
the.status
keyjoin()
on the.display
to get single value instead of the array.
Output:
{
"computers": {
"host": "example",
"platform": "some_platform",
"description": "",
"working": "yes",
"display": "no"
}
}
JqPlay Demo
If there could be multiple objects in the computer
array, first
will ensure the first object is used.
We could also use last
to get the last one:
.computers |= (last | . .status | del(.status) | (.display |= join(.)))
Or combine map()
and add
to loop over all the objects, and add them together, then the the keys will be overwritten so the last value will stay visible, this might be handy if not all the objects have all the keys:
.computers |= (map(. .status | del(.status) | (.display |= join(.))) | add)
CodePudding user response:
If your JSON structure is fixed, the following could do:
.computers
| first
| { host, platform, description }
(.status | .display |= first)
| { computers: . }
or
.computers
| first
| del(.status) (.status | .display |= first)
| { computers: . }
or
{
computers: (
.computers[0] | del(.status) (.status | .display |= first)
)
}
Output:
{
"computers": {
"host": "example",
"platform": "some_platform",
"description": "",
"working": "yes",
"display": "no"
}
}
Another alternative is reassigning the computers property, similar to 0stone0's solution, but a little bit shorter:
.computers |= (first | del(.status) (.status | .display |= first))