Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update a jsonb column's field in PostgreSQL?

So I wanted to try jsonb of PostgreSQL. In my table, I have a column called extras of jsonb type.

Sample data in extras looks like {"param1": 10, "param2": 15}

I would like to modify the JSON using sql statements only. I want to do something like this:

Update param1 of extras field by adding 10 to its value if param2 of extras exceeds 12.

How can I write a SQL statement like this? I know I can easily do this in the application layer but I would like to do this in the SQL layer itself as the number of rows I would be potentially dealing with would be huge and I do not want to waste time in db-application-db roundtrip

like image 766
Ranjith Ramachandra Avatar asked May 06 '15 10:05

Ranjith Ramachandra


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 update a field in JSON?

To update JSON data in a table: Query and retrieve the JSON data from a JSON column. Modify the contents of the JSON column. To push the updated column value back into the table, issue the UPDATE SQL statement and specify the JSON2BSON function.

Can you index Jsonb Postgres?

JSONB and IndexesPostgreSQL can use indexes for the text results as compare operands. GIN index can be used by the GIN JSONB operator class.


2 Answers

This should do it with PostgreSQL 9.5:

create table t (extras jsonb);
insert into t values
    ('{"param1": 10, "param2": 15}'),
    ('{"param1": 10, "param2": 5}');

UPDATE t 
  SET extras = jsonb_set(extras, '{param1}', ((extras->>'param1')::real + 10)::text::jsonb) 
  WHERE (extras#>>'{param2}')::real > 12;

select * from t;
            extras            
------------------------------
 {"param1": 10, "param2": 5}
 {"param1": 20, "param2": 15}
(2 rows)
like image 151
Mikael Lepistö Avatar answered Oct 08 '22 20:10

Mikael Lepistö


The jsonb type is meant to store whole documents. If you change any part of the document, you'll need to assign a new value to the column. Because Postgres keeps the old version around for a while that is an expensive operation.

With that in mind, here's an example of how not to update jsonb columns:

create table t1 (doc jsonb);

insert into t1 values 
    ('{"param1": 10, "param2": 15}'),
    ('{"param1": 10, "param2": 5}');

update  t1
set     doc = ('{"param1": ' ||
        ((doc->'param1')::text::int + 10)::text ||
        ', "param2": ' ||
        (doc->'param2')::text ||
        '}')::jsonb
where   (doc->'param2')::text::int > 12;

select * from t1;

This prints:

            doc
------------------------------
 {"param1": 10, "param2": 5}
 {"param1": 20, "param2": 15}
(2 rows)
like image 23
Andomar Avatar answered Oct 08 '22 22:10

Andomar