Use jq
to alter nested objects in json files
March 26, 2021 (modified April 1, 2021)
Given a document structured like this, that is, containing an array of objects holding nested objects as properties
{ "property-1": "value", "property-2": "value", "array": [ { "stringprop": "value", "obj-1": { "sprop-1": "value", "sprop-2": "value" }, "obj-2": { "sprop-1": "value", "sprop-2": "value" }, }, { "stringprop": "value", "obj-1": { "sprop-1": "value", "sprop-2": "value" }, "obj-2": { "sprop-1": "value", "sprop-2": "value" }, }, ... ] }
the task at hand is to add sprop-3
to all nested objects in array
so that we end up with this
{ "property-1": "value", "property-2": "value", "array": [ { "stringprop": "value", "obj-1": { "sprop-1": "value", "sprop-2": "value", "sprop-3": "value" }, "obj-2": { "sprop-1": "value", "sprop-2": "value", "sprop-3": "value" }, }, { "stringprop": "value", "obj-1": { "sprop-1": "value", "sprop-2": "value", "sprop-3": "value" }, "obj-2": { "sprop-1": "value", "sprop-2": "value", "sprop-3": "value" }, }, ... ] }
jq
does this with the following filter set:
jq '.changeset = [ .changeset[] | .[] |= if (type == "string") then . else (. += {"extra": "stuff"}) end]'
Format that slightly differently to allow a line by line explanation
jq '.array = # replace array with [ # a new array that includes .array[] # every old element | .[] # for all properties of the element |= # replace the property with if (type == "string") # is it a string value? then . # then itself else (. += {"sprop-3": "value"}) # else the current value with the new propery added end ]'
This took me a little while to figure out. The pipe symbol introduces
a new context, where the dot .
stands for every result of the filter
left of the pipe.