Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL rename attribute in jsonb field

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"}
like image 518
T. Kong Avatar asked Feb 17 '17 22:02

T. Kong


People also ask

Should I use JSON or Jsonb Postgres?

PostgreSQL jsonb Json preserves the original formatting like the whitespaces as well as the ordering of keys. Jsonb does not preserve the original formatting of text like the whitespaces and the ordering of keys. Json processes input faster than jsonb as there is no conversion involved in this.

What is Jsonb data type in PostgreSQL?

The jsonb datatype is an advanced binary storage format with full processing, indexing and searching capabilities, and as such pre-processes the JSON data to an internal format, which does include a single value per key; and also isn't sensible to extra whitespace or indentation.

Is Postgres Jsonb fast?

Speed. Because JSONB stores data in a binary format, queries process significantly faster. Storing data in binary form allows Postgres to access a particular JSON key-value pair without reading the entire JSON record.

Is Jsonb efficient?

Most applications should use JSONB for schemaless data. It stores parsed JSON in a binary format, so queries are efficient.


3 Answers

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)
like image 88
klin Avatar answered Oct 21 '22 09:10

klin


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:

  • #- Delete the field or element with specified path (for JSON arrays, negative integers count from the end) https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSONB-OP-TABLE

  • #>Get JSON object at the specified path https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-JSON-OP-TABLE

like image 22
emlai Avatar answered Oct 21 '22 08:10

emlai


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 *;
like image 35
rocksteady Avatar answered Oct 21 '22 10:10

rocksteady