Postgres Обновление нескольких ключей jsonb_set

У меня есть таблица DB с столбцом jsonb.

number  | data
    1   | {"name": "firstName", "city": "toronto", "province": "ON"}

Мне нужен способ обновить столбец данных. Поэтому мой вывод должен выглядеть так:

{"name": "firstName", "city": "ottawa", "province": "ON", "phone": "phonenum", "prefix": "prefixedName"}

Возможно ли это с помощью json_set? Я добавил запрос как:

update table_name set data = jsonb_set(data, '{city}', '"ottawa"') where number = 1;

Однако мне нужен способ добавить новое значение ключа, если оно не существует, и обновить значение ключа, если оно существует. Можно ли добиться этого в одном запросе?

Ответ 1

Документация :

|| оператор конкатенирует элементы на верхнем уровне каждого из своих операндов.... Например, если оба операнда представляют собой объекты с общим именем поля ключа, значение поля в результате будет просто значением из правого операнда.

Итак, используя данные вашего примера:

update table_name set
  data = data || '{"city": "ottawa", "phone": "phonenum", "prefix": "prefixedName"}'
where number = 1;

Кроме того, если объект, который вы хотите отредактировать, находится не на верхнем уровне - просто объедините функцию конкатенации и jsonb_set. Например, если исходные данные выглядят как

{"location": {"name": "firstName", "city": "toronto", "province": "ON"}}

затем

...
data = jsonb_set(data, '{location}', data->'location' || '{"city": "ottawa", "phone": "phonenum", "prefix": "prefixedName"}')
...

Ответ 2

Вы можете попробовать это

Здесь мы используем оператор jsonb concatation || для объединения двух jsonb-объектов

update table_name set data = (select val from (
(select 
CASE WHEN data ? key THEN jsonb_set(data, '{' || key || '}', quote_nullable(updated_value))
ELSE 
data || ('{' || quote_ident(key) || ':' || quote_ident(some_value) || '}')::jsonb
END val
 from json_each_text((select data::json from tbl))
CROSS JOIN tbl t
where key in ('city','phone','prefix') and number=1)) where number=1