Обновить элемент списка jsonb в PostgreSQL

#sql #arrays #json #postgresql #postgresql-9.5

#sql #массивы #json #postgresql #postgresql-9.5

Вопрос:

Я пытаюсь обновить имя ключа 1 поля в моем jsonb списке.

Исходные данные

 select jsonb_array_elements(status_history) from deals;
>>> [{"date": "2020-10-02T12:05:02.728691", "state": "gathering_info"}, {"date": "2020-10-08T10:15:20.798500", "state": "archived"}, {"date": "2020-10-08T10:43:17.651033", "state": "gathering_info"}]
>>> ...
 

Я могу получить каждый элемент с помощью этой функции

 select jsonb_array_elements(status_history) from deals;

>>> {"date": "2020-10-02T11:51:55.624263", "state": "gathering_info"}
 

Я хочу обновить state ключ, чтобы он был status , и я пытаюсь это сделать

 update deals set elem=elem amp; {'status': elem->'state'} from (select jsonb_array_elements(status_history) from deals) elem;
update deals set elem->'status' = elem->'state' from (select jsonb_array_elements(status_history) from deals) elem;
 

Но это не работает. Как я могу это сделать?

Ответ №1:

Вы можете отменить проверку массива, отслеживая положение каждого объекта, изменить имя ключа в каждом отдельном элементе с помощью операторов - , а || затем повторно сгруппировать. Предполагая, что первичный ключ вашей таблицы id , вы могли бы сформулировать это как:

 update deals d
set status_history = d1.status_history
from (
    select d.id, 
        json_agg(
            x.obj - 'state' || jsonb_build_object('status', x.obj -> 'state')
            order by x.n
        ) as status_history
    )
    from deals d
    cross join lateral jsonb_array_elements(d.status_history) with ordinality as x(obj, n)
    group by d.id
) d1
where d1.id = d.id