Search Postgresql Archives

Re: jsonb_set for nested new item?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am 23.09.16 um 16:14 schrieb Deven Phillips:

> Is there a way to set a nested element for which the parent paths do not
> yet exist?
>
> For example, if I have a JSONB value called 'data':
>
> {
>     "foo": "bar"
> }
>
> and run
>
> jsonb_set(data, {'boo', 'baz'}, 'newvalue')
>
> I would expect the output to be:
>
> {
>     "foo": "bar",
>     "boo": {
>         "baz": "newvalue"
>      }
> }
I don't know why jsonb_set() does not simply allow
SELECT jsonb_set('{"foo": "bar"}'::jsonb, '{boo,baz}', '"newvalue"');
even not in PostgreSQL 9.6.

The trick for now is to use JSONB operators to get the (maybe existing)
old 1st-level value and insert/overwrite the 2nd-level key.

-- 1st-level key 'boo' does not exist
WITH jsonb_table AS (SELECT '{"foo": "bar"}'::jsonb AS jsonb_column)
SELECT jsonb_column, jsonb_set(jsonb_column, '{boo}',
coalesce(jsonb_column->'boo', '{}) || '{"baz": "newvalue"}') FROM
jsonb_table;

  jsonb_column  |                 jsonb_set                 
----------------+--------------------------------------------
 {"foo": "bar"} | {"boo": {"baz": "newvalue"}, "foo": "bar"}

-- 2nd-level key 'baz' does not exist (but other keys)
WITH jsonb_table AS (SELECT '{"foo": "bar", "boo": {"otherkey":
"othervalue"}}'::jsonb AS jsonb_column)
SELECT jsonb_column, jsonb_set(jsonb_column, '{boo}',
coalesce(jsonb_column->'boo', '{}') || '{"baz": "newvalue"}') FROM
jsonb_table;

                   jsonb_column                   
|                              jsonb_set                              
---------------------------------------------------+----------------------------------------------------------------------
 {"boo": {"otherkey": "othervalue"}, "foo": "bar"} | {"boo": {"baz":
"newvalue", "otherkey": "othervalue"}, "foo": "bar"}


-- 2nd-level key 'baz' exists (and other keys)
WITH jsonb_table AS (SELECT '{"foo": "bar", "boo": {"baz": "oldvalue",
"otherkey": "othervalue"}}'::jsonb AS jsonb_column)
SELECT jsonb_column, jsonb_set(jsonb_column, '{boo}',
coalesce(jsonb_column->'boo', '{}') || '{"baz": "newvalue"}') FROM
jsonb_table;

                             jsonb_column                            
|                              jsonb_set                              
----------------------------------------------------------------------+----------------------------------------------------------------------
 {"boo": {"baz": "oldvalue", "otherkey": "othervalue"}, "foo": "bar"} |
{"boo": {"baz": "newvalue", "otherkey": "othervalue"}, "foo": "bar"}

Please note that the actual jsonb_set() call is always the same, only
jsonb_column changes to show all possible cases.
The 2 JSONB literals empty/new in the jsonb_set() call need no casting,
just the jsonb_column for the -> operator and jsonb_set() to work
(already done in the WITH clause).

The WITH clause is just there for this example, otherwise you would have
to duplicate the same value. Just use your existing JSONB column instead.

JSONB sorts the keys in alphanumerical order, so don't get confused by
the insert positions.


-- 
Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux