Reputation: 13
I have a json column in a postgres table. The column contains the following json data:
{
"data": {
"id": "1234",
"sites": [
{
"site": {
"code": "1",
"display": "Site1"
}
},
{
"site": {
"code": "2",
"display": "Site2"
},
"externalSite": true
},
{
"site": {
"code": "3",
"display": "Site3"
}
}
]
}
}
I need to create an update query that adds another attribute ('newAttribute' in the sample below) to all array items that have '"externalSite": true', so, after running the update query the second array element will be:
{
"site": {
"code": "2",
"display": "Site2"
},
"externalSite": true,
"newAttribute": true
}
The following query returns the array elements that need to be updated: select * from myTable, jsonb_array_elements(data -> 'sites') sites where sites ->'externalSite' = 'true'
What is the syntax of the update query?
Thanks Kobi
Upvotes: 1
Views: 78
Reputation: 6723
Assuming your table is called test
and your column is called data
, you can update it like so:
UPDATE test SET data =
(select jsonb_set(data::jsonb, '{"data","sites"}', sites)
FROM test
CROSS JOIN LATERAL (
SELECT jsonb_agg(CASE WHEN site ? 'externalSite' THEN site || '{"newAttribute":"true"}'::jsonb
ELSE site
END) AS sites
FROM jsonb_array_elements( (data#>'{"data","sites"}')::jsonb ) as ja(site)
) as sub
);
Note that I cast the data to jsonb data as there are more functions and operators available for manipulating jsonb than plain json.
You can run the SELECT statement alone to see what it is doing, but the basic idea is to re-create the sites
object by expanding it with jsonb_array_elements and adding the newAttribute
attribute if externalSite
exists.
This array is then aggregated with jsonb_agg and, finally, in the outer select, the sites
object is replaced entirely with this newly computed version.
Upvotes: 0