I have a table mapping_transform
with a JSONB column content_json
containing something like
{
"meta": {...},
"mapping": [
...,
{
"src": "up",
"dest": "down",
...
},
...
]
}
I want to add a new JSON entry ("rule_names": [ "some name" ]
) to the JSON object matching src
= up
and dest
= down
, which would result in
{
"meta": {...},
"mapping": [
...,
{
"src": "up",
"dest": "down",
...,
"rule_names": [ "some name" ]
},
...
]
}
The following query returns the JSON object that meets the filter requirements:
WITH elems AS (SELECT json_array_elements(content_json->'mapping') from mapping_transform)
SELECT * FROM elems WHERE json_array_elements->>'src' = 'up' and json_array_elements->>'dest' = 'down';
-- Alternative
SELECT mt_entry
FROM mapping_transform,
LATERAL jsonb_array_elements(content_json::jsonb->'mapping') mt_entry
WHERE mt_entry->>'src' = 'up' and mt_entry->>'dest' = 'down';
My problem now is that I do not know how to add the new entry to the specific object. I tried something like
WITH elems AS (SELECT json_array_elements(content_json->'mapping') from mapping_transform),
results SELECT * FROM elems WHERE json_array_elements->>'src' = 'up' and json_array_elements->>'dest' = 'down'
UPDATE mapping_transform
SET content_json = jsonb_set(results, '{"rule_names"}', '["some name"]'); -- this does obviously not work
but that does not execute as results
is an unknown column. I also do need to merge the result of the jsonb_set
with the rest of the content_json
before assigning to content_json
, because otherwise it would override the whole content.
How can I update specific deeply nested JSON objects based on filter criteria? If I had a well defined path as to where my object is that I want to update, things would be much easier. But as the target object lies within a JSON array and has an arbitrary position, finding and updating it is much more difficult.