8

Say I have a table on Postgres with a jsonb column containing {"a": 1, "b": 2}. Now I'd like to upsert a record with the same id and {"b": 10, "c": 20} as the jsonb column value.

Consequently, I'd like the jsonb field of the row to contain {"a": 1, "b": 10, "c": 20}. How can this be achieved?

3 Answers 3

11

If you want an "upsert", you can do this with insert ... on conflict...

insert into the_table (id, json_column)
values (1, '{"b": 10, "c": 20}'::jsonb)
on conflict (id) do update
   set json_column = table_name.json_column || excluded.json_column;
Sign up to request clarification or add additional context in comments.

Comments

10

If concatenate 2 jsonb value, you achieve what you want, for example:

select '{"a": 1, "b": 2}'::jsonb  || '{"b": 10, "c": 20}'::jsonb 

produces: "{"a": 1, "b": 10, "c": 20}"

if both operands are objects with a common key field name, the value of the field in the result will just be the value from the right hand operand.

https://www.postgresql.org/docs/current/static/functions-json.html

3 Comments

Thanks! How would I go about upserting the new jsonb object such that the old and new one get concatenated?
If you need update existing jsonb value then you can do: uptade table_name set col = col || '{"b": 10, "c": 20}'::jsonb where id = ?
This will only concatenate shallowly, right? Deeply nested JSON objects are not merged recursively.
2

Well, my example is not about merging 2 json fields, but arrays instead:

insert into tag_lists (article_id, tags) values (1, '{job}')
on conflict (article_id)
do update set tags = (
  select array_agg(distinct x) from unnest(tag_lists.tags || excluded.tags) x
);

Thanks to this answer for providing comprehensive snippets

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.