Делать UPSERT на основе заданного c значения JSON в Postgres 10 - PullRequest
0 голосов
/ 13 марта 2020

У меня есть Postgres таблица messages следующим образом:

Column   |           Type             | Collation | Nullable |                    
-----------+--------------------------+-----------+----------
 id        | integer                  |           | not null |
 message   | jsonb                    |           |          | 
 date      | timestamp with time zone |           | not null | 
id | message                      | date
1  | {"name":"alpha", "pos":"x"}  | 2020-02-11 12:31:44.658667+00
2  | {"name":"bravo", "pos":"y"}  | 2020-02-11 12:32:43.123678+00
3  | {"name":"charlie", "pos":"z"}| 2020-02-11 12:38:37.623535+00

Что я хотел бы сделать, это сделать UPSERT на основе значения клавиши name, т. Е. если есть вставка с таким же значением name, тогда обновляется другое значение pos, в противном случае создается новая запись.

Я сделал CREATE UNIQUE INDEX message_name ON messages((message->>'name'));

Я нашел ВСТАВИТЬ В КОНФЛИКТ в Postgres 9,5+, но я не могу понять, как использовать уникальный индекс с этим.

Я не знаю, является ли это правильным подходом, чтобы сделать это в первое место, так что если есть лучший способ сделать это, я был бы признателен за ввод.

1 Ответ

4 голосов
/ 13 марта 2020

Вам нужно повторить выражение из индекса:

insert into messages (message)
values ('{"name":"alpha", "pos":"new pos"}')
on conflict ((message->>'name')) 
  do update 
     set message = jsonb_set(messages.message, '{pos}'::text[], excluded.message -> 'pos', true)
;

Если у вас есть еще ключи в JSON и вы хотите заменить (или добавить) все из них, вы можете использовать это:

insert into messages (message)
values ('{"name":"alpha", "pos":"new pos", "some key": 42}')
on conflict ((message->>'name')) 
  do update 
     set message = messages.message || (excluded.message - 'name')
;
...