Это очень уродливо и показывает случай использования, когда денормализация модели с использованием JSON является плохим выбором (если бы это было правильное отношение один-ко-многим, столбец font_size
был бы определен как целое число, иу вас не возникло бы этой проблемы для начала).
Единственное, о чем я могу думать, - это разложить все элементы массива, изменить значение на целое, объединить «виджеты» обратно вмассив и использовать его для обновления таблицы.
В следующем коде предполагается, что в вашей таблице есть столбец первичного ключа с именем id
.
Первый шаг - заменить значение fontSize на правильное целое число.
select t.id, jsonb_set(w.jw, '{fontSize}', to_jsonb((w.jw ->> 'fontSize')::int))
from the_table t
cross join jsonb_array_elements(t.the_value -> 'resources' -> 'widgets') as w(jw)
jsonb_array_elements()
возвращает каждый виджет как одно значение JSONB (в отдельной строке). to_jsonb((w.jw ->> 'fontSize')::int
преобразует текущее значение ключа fontSize
в целое число, а jsonb_set()
возвращает его обратно в значение JSON.
При получении данных примера это возвращает (включая предполагаемый столбец первичного ключа)
id | jsonb_set
---+------------------------------------------------------------
42 | {"id": 1, "color": "#ffffff", "width": 150, "fontSize": 5}
42 | {"id": 2, "color": "#aaaaaa", "width": 200, "fontSize": 10}
Теперь это можно объединить обратно в массив:
select t.id, jsonb_agg(jsonb_set(w.jw, '{fontSize}', to_jsonb((w.jw ->> 'fontSize')::int))) as new_widgets
from the_table t
cross join jsonb_array_elements(t.the_value -> 'resources' -> 'widgets') as w(jw)
group by id
Учитывая приведенную выше дату выборки, теперь возвращается:
id | new_widgets
---+---------------------------------------------------------------------------------------------------------------------------
42 | [{"id": 1, "color": "#ffffff", "width": 150, "fontSize": 5}, {"id": 2, "color": "#aaaaaa", "width": 200, "fontSize": 10}]
Этот запрос теперь можно использоватьв качестве источника для оператора UPDATE, который снова использует jsonb_set()
для изменения значения в таблице.
update the_table
set the_value = jsonb_set(the_value, '{resources, widgets}', x.new_widgets)
from (
select t.id, jsonb_agg(jsonb_set(w.jw, '{fontSize}', to_jsonb((w.jw ->> 'fontSize')::int))) as new_widgets
from the_table t
cross join jsonb_array_elements(t.the_value -> 'resources' -> 'widgets') as w(jw)
group by id
) as x
where x.id = the_table.id;
Полный онлайн-пример: https://rextester.com/OIFOBX92774
Если ваш столбецне определен как jsonb
(что и должно быть), вам нужно привести его the_column::jsonb
в вышеупомянутых запросах.