In PostgreSQL, I have a table named users
with data that looks like so:
id | favorites |
---|---|
1 | { "shapes": ["Triangle", "Square"] } |
2 | { "shapes": ["Rectangle", "Triangle"] } |
… | … |
Where favorites
is a JSONB
column.
I want to add shapes "Rectangle" and "Circle" to all users’ favorite shapes but without duplication. The output table should look like so:
id | favorites |
---|---|
1 | { "shapes": ["Triangle", "Square", "Rectangle", "Circle"] } |
2 | { "shapes": ["Rectangle", "Triangle", "Circle"] } |
… | … |
How do I do that in one query?
Limitations:
- The
favorites
object contains other fields thanshapes
and therefore cannot be converted into an array of strings. - The update must be in one query
- If the input array contains an element that is already in a row’s
shapes
array, it must append only the ones that are not already inshapes
.
2
Answers
This can be done using
jsonb_set
and the operator||
, but before insert any data we need to check if it is already in the array or not, to do so we can use the operator@>
:Demo here
This is an other solution more readable using
jsonb_array_elements
andjsonb_agg
to make sure the new added elements not exists :Demo 2 here
Instead of the update, you can use for example
"SELECT * FROM step1"
to see what happens at each step.Step1: Unnest the shapes, and concat them with the parameters
Step2: Keep only distinct
Step3: Rebuild the json property
Update step: Update just the property needed, without harming any other properties you may have stored in that column (credits: https://dba.stackexchange.com/a/295300/246773)
Fiddle: https://www.db-fiddle.com/f/4jyoMCicNSZpjMt4jFYoz5/8340