Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update certain array elements of a json array in PostgreSQL 9.4

I have a table like this;

CREATE TABLE test (
  id BIGSERIAL PRIMARY KEY,
  data JSONB
);

INSERT INTO test(data) VALUES('[1,2,"a",4,"8",6]'); -- id = 1
INSERT INTO test(data) VALUES('[1,2,"b",4,"7",6]'); -- id = 2

How to update element data->1 and data->3 into something else without PL/*?

like image 472
Kokizzu Avatar asked Dec 04 '14 07:12

Kokizzu


People also ask

How do you update objects in Jsonb arrays with PostgreSQL?

Postgres offers a jsonb_set function for updating JSON fields. The second parameter path defines, which property you want to update. To update items in an array, you can use an index-based approach. To update the first entry in the items array in the example above, a path woud look like this: {items, 0, customerId} .

How do I query Jsonb data in PostgreSQL?

Querying the JSON documentPostgreSQL has two native operators -> and ->> to query JSON documents. The first operator -> returns a JSON object, while the operator ->> returns text. These operators work on both JSON as well as JSONB columns. There are additional operators available for JSONB columns.

What is -> in PostgreSQL?

Operator ->>Allows you to select an element within an array based on its index. Cannot be used sequentially. Return type is text and the result can be used with functions and operators that require a string-based datatype. For the same reason, sequential usage of the operator is not supported.


1 Answers

For Postgres 9.5 or later use jsonb_set(). See later answer of adriaan.


You cannot manipulate selected elements of a json / jsonb type directly. Functionality for that is still missing in Postgres 9.4. You have to do 3 steps:

  1. Unnest / decompose the JSON value.
  2. Manipulate selected elements.
  3. Aggregate / compose the value back again.

To replace the 3rd element of the json array (data->3) in the row with id = 1 with a given (new) value ('<new_value>'):

UPDATE test t
SET    data = t2.data
FROM  (
   SELECT id, array_to_json(
                 array_agg(CASE WHEN rn = 1 THEN '<new_value>' ELSE elem END))
              ) AS data
   FROM   test t2
        , json_array_elements_text(t2.data) WITH ORDINALITY x(elem, rn)         
   WHERE  id = 1
   GROUP  BY 1
   ) t2
WHERE  t.id = t2.id
AND    t.data <> t2.data; -- avoid empty updates

About json_array_elements_text():

  • How to turn JSON array into Postgres array?

About WITH ORDINALITY:

  • PostgreSQL unnest() with element number
like image 60
Erwin Brandstetter Avatar answered Oct 06 '22 01:10

Erwin Brandstetter