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
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} .
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.
JSONB and IndexesPostgreSQL can use indexes for the text results as compare operands. GIN index can be used by the GIN JSONB operator class.
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)
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With