1

I got a json type column named 'attr' which was used to store a list include some dict like [{"foo":1}, {"foo":2}, {"foo":3}].

Now I want to extend the list to [{"foo":1}, {"foo":2}, {"foo":3}, {"foo":4}]. Of course I can use a sql query like:

update tbl
set attr='[{"foo":1}, {"foo":2}, {"foo":3}, {"foo":4}]'::json;

However, I need execute it in my webserver. So I must select the former value, extend the list and then update into table.

I'm thinking if there is a way to use some postgresql function to do this like array_to_json or json_array_elements

I wrote this query:

update tbl
set attr = json_build_array(json_array_elements(attr), '{"foo":4}'::json);

But it got wrong result.

1 Answer 1

2

For the data type json:

UPDATE tbl
SET    attr = (
   SELECT json_agg(elem)
   FROM  (
      SELECT elem
      FROM   json_array_elements(attr) elem
      UNION  ALL
      SELECT '{"foo":4}'::json
      ) sub
   )
WHERE  tbl_id = 123;  -- determine row to update

For the data type jsonb:

UPDATE tbl
SET    attr = (
   SELECT json_agg(elem)::jsonb
   FROM  (
      SELECT elem
      FROM   jsonb_array_elements(attr) elem
      UNION  ALL
      SELECT '{"foo":4}'::jsonb
      ) sub
   )
WHERE  tbl_id = 123;

The aggregate function json_agg() always returns json, even when called with jsonb input. So we need another cast to jsonb.

Obviously you want to limit your UPDATE to a specific row, so add a WHERE clause.

Don't go to the underlying table a second time in the subselect, just work with the value from the target row.

Sign up to request clarification or add additional context in comments.

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.