I have a table with two columns and the following data. I’m stuck with this table’s structure and have no possibility of revamping it since the company has grown significantly and a lot of features depend on that particular format.
id (long) | steps (jsonb) |
---|---|
1 | {"uuid1": {"value1":[10]}, "uuid2": {"value45":1}} |
2 | {"uuid3": {"value1":[1]}, "uuid4": {"value1":[3]} |
And i want to update these data to get the following table (transforming the array in "value1" to a scalar):
id (long) | steps (jsonb) |
---|---|
1 | {"uuid1": {"value1":10}, "uuid2": {"value45":1}} |
2 | {"uuid3": {"value1":1}, "uuid4": {"value1":3} |
The problem is with the uuid key of the top-level dictionnary. I can’t manage to get the expected result when there are multiple "value1" key in a single row.
Thanks to this question, I got the following request:
with s AS (
SELECT
a.id,
ARRAY[key,'value1'] as path,
value#>'{value1}'->0 as value
FROM a, jsonb_each(steps)
WHERE (value->'value1') IS NOT NULL
AND value#>'{value1}'->0 IS NOT NULL
)
UPDATE a
SET steps = jsonb_set(a.steps, s.path, s.value)
FROM s
WHERE s.id = a.id;
The s table has 3 rows:
id (long) | path | value |
---|---|---|
1 | "uuid1" | 10 |
2 | "uuid3" | 1 |
2 | "uuid4" | 3 |
However, this only modifies one record at a time. How can I modify my request so that all "value1" nested key in a single row get updated?
Thank you for your time.
2
Answers
The query works but it looks like a monster.. To avoid such queries you need to normalize your DB as it was mentioned in the comment section.
Demo
Main idea:
value1
value which need to be updated.jsonb
pieces using previously detected key-value pairs.jsonb
field keys which need to be updated, so we get ‘immutable’ part of the originaljsonb
.jsonb
: merge updatedjsonb
pieces with immutable ones (step 3 and 4 respectively).The caveat is that the order of the key-value pairs in the final
jsonb
may differ from the original.Using two subqueries with
jsonb_each
:See fiddle