With postgresql 9.3 I can SELECT
specific fields of a JSON data type, but how do you modify them using UPDATE
? I can't find any examples of this in the postgresql documentation, or anywhere online. I have tried the obvious:
postgres=# create table test (data json);
CREATE TABLE
postgres=# insert into test (data) values ('{"a":1,"b":2}');
INSERT 0 1
postgres=# select data->'a' from test where data->>'b' = '2';
?column?
----------
1
(1 row)
postgres=# update test set data->'a' = to_json(5) where data->>'b' = '2';
ERROR: syntax error at or near "->"
LINE 1: update test set data->'a' = to_json(5) where data->>'b' = '2...
Update: With PostgreSQL 9.5, there are some
jsonb
manipulation functionality within PostgreSQL itself (but none forjson
; casts are required to manipulatejson
values).Merging 2 (or more) JSON objects (or concatenating arrays):
So, setting a simple key can be done using:
Where
<key>
should be string, and<value>
can be whatever typeto_jsonb()
accepts.For setting a value deep in a JSON hierarchy, the
jsonb_set()
function can be used:Full parameter list of
jsonb_set()
:path
can contain JSON array indexes too & negative integers that appear there count from the end of JSON arrays. However, a non-existing, but positive JSON array index will append the element to the end of the array:For inserting into JSON array (while preserving all of the original values), the
jsonb_insert()
function can be used (in 9.6+; this function only, in this section):Full parameter list of
jsonb_insert()
:Again, negative integers that appear in
path
count from the end of JSON arrays.So, f.ex. appending to an end of a JSON array can be done with:
However, this function is working slightly differently (than
jsonb_set()
) when thepath
intarget
is a JSON object's key. In that case, it will only add a new key-value pair for the JSON object when the key is not used. If it's used, it will raise an error:Deleting a key (or an index) from a JSON object (or, from an array) can be done with the
-
operator:Deleting, from deep in a JSON hierarchy can be done with the
#-
operator:For 9.4, you can use a modified version of the original answer (below), but instead of aggregating a JSON string, you can aggregate into a json object directly with
json_object_agg()
.Original answer: It is possible (without plpython or plv8) in pure SQL too (but needs 9.3+, will not work with 9.2)
SQLFiddle
Edit:
A version, which sets multiple keys & values:
Edit 2: as @ErwinBrandstetter noted these functions above works like a so-called
UPSERT
(updates a field if it exists, inserts if it does not exist). Here is a variant, which onlyUPDATE
:Edit 3: Here is recursive variant, which can set (
UPSERT
) a leaf value (and uses the first function from this answer), located at a key-path (where keys can only refer to inner objects, inner arrays not supported):Updated: Added function for replacing an existing json field's key by another given key. Can be in handy for updating data types in migrations or other scenarios like data structure amending.
Update: functions are compacted now.