PostgreSQL rename attribute in jsonb field
Asked Answered
B

3

71

In PostgreSQL 9.5, is there a way to rename an attribute in a jsonb field?

For example:

{ "nme" : "test" }

should be renamed to

{ "name" : "test"}
Belfort answered 17/2, 2017 at 22:53 Comment(2)
Take a look at string replacement (dba.stackexchange.com/a/172601/41320)Manton
similar question added #59909176Gilles
F
136

In UPDATE use delete (-) and concatenate (||) operators, e.g.:

create table example(id int primary key, js jsonb);
insert into example values
    (1, '{"nme": "test"}'),
    (2, '{"nme": "second test"}');

update example
set js = js - 'nme' || jsonb_build_object('name', js->'nme')
where js ? 'nme'
returning *;

 id |           js            
----+-------------------------
  1 | {"name": "test"}
  2 | {"name": "second test"}
(2 rows)
Flick answered 17/2, 2017 at 23:4 Comment(6)
In case somebody wonders, returning * is not mandatory for the query to work. It only causes a display (like a select) of all updated rows, that is, all rows.Oarlock
@klin: I tried your query it works. But is there any way that we get ids in {} and not simply mentioned in double quotes? rextester.com/HQS81928Tannenwald
@PranavUnde - please ask a new question with an appropriate example.Flick
Its works fine, can you please tell how to update nested objects like {"skill":{"c":{"name":"C", "code":"c"}}}, how to update c attribute inside skill.Detain
Found the solution, first add the object with new attribute and then remove the existing attribute. something like this. update example SET js = JSONB_SET(js::JSONB, '{skill,c++}', js->'skill'->'c', true) where js->'skill' ? 'c'; update example SET js = js#-'{skill, c}' where js->'skill' ? 'c';Detain
This is awesome, thanks! Here's an example with Rails ActiveRecord for anyone it may help: todayilearned.fyi/by/odlp/…Upbear
C
31

I used the following for handling nested attributes and skipping any json that doesn't use the old name:

UPDATE table_name
SET json_field_name = jsonb_set(json_field_name #- '{path,to,old_name}',
                                '{path,to,new_name}',
                                json_field_name#>'{path,to,old_name}')
WHERE json_field_name#>'{path,to}' ? 'old_name';

just for reference docs:

Converge answered 15/5, 2018 at 14:14 Comment(2)
That worked for me, although I messed up the first entry of {path, to, old_name} it didn't seem to affect the result and I still got the right thingTransudate
@MatheusFelipe, can you please help me. I need to change LicenseDate to LicenseExpirationDate UPDATE dbo."dcp_OrgLevelEntityItems" SET "Attributes" = jsonb_set("Attributes" => '{LicenseDate}', '{LicenseExpirationDate}') WHERE "Id" = 1 Sample JSON - Column name is Attributes { "Name": "LIC", "Street": 223871, "City": 59390, "LicenseDate": "01092019" }Speedometer
G
16

This is an old question, but still comes up high in the search rankings for this particular task. One approach that isn't all that JSON-ey but can still be a decent solution (if there is a minimal risk of key-naming collision) is to handle the field as TEXT, do a replace (could be a regex too) and then cast back to JSON.

Something like this, borrowing @klin's setup:

CREATE TABLE example(id INT PRIMARY KEY, js JSONB);
INSERT INTO example VALUES
    (1, '{"nme": "test"}'),
    (2, '{"nme": "second test"}');

UPDATE EXAMPLE
SET js = (REPLACE(js::TEXT, '"nme"', '"name"'))::JSONB
RETURNING *;
Gaol answered 22/6, 2022 at 15:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.