在jsonb列中更新键值?

时间:2016-01-18 08:23:19

标签: postgresql jsonb

我们说我们有一张桌子 -

create table test_table(id text not null, data jsonb not null)

我们的价值观为 -

insert into test_table values('data1', '{"name": "Rahul Jain", "emp_id": "73347", "attributes": [{"key": "name", "value": "Amay Adams", "display_name": "Name"}, {"key": "designation", "value": "Senior Software Engineer", "display_name":"Designation"}, {"key": "location", "value": "New Delhi", "display_name": "Location"}, {"key": "dept", "value": "Engineering", "display_name": "Department"}, {"key": "dept", "value": "Engineering", "display_name": "Department"}]}')

现在这个表有数百万条记录。我必须更新密钥dept的值,即从Engineering更新为Technology。我不想使用python脚本来获取值,然后检查密钥然后更新。如何为其进行就地更新,通过某些查询进行更新?外键的更新看似合理,但对于attributes数组,我找不到任何方法。

1 个答案:

答案 0 :(得分:0)

Well, I believe you can do this using plpgsql, but it can be tricky:

=# select jsonb_pretty(data) from test_table;
                   jsonb_pretty                   
--------------------------------------------------
 {                                               +
     "name": "Rahul Jain",                       +
     "emp_id": "73347",                          +
     "attributes": [                             +
         {                                       +
             "key": "name",                      +
             "value": "Amay Adams",              +
             "display_name": "Name"              +
         },                                      +
         {                                       +
             "key": "designation",               +
             "value": "Senior Software Engineer",+
             "display_name": "Designation"       +
         },                                      +
         {                                       +
             "key": "location",                  +
             "value": "New Delhi",               +
             "display_name": "Location"          +
         },                                      +
         {                                       +
             "key": "dept",                      +
             "value": "Engineering",             +
             "display_name": "Department"        +
         },                                      +
         {                                       +
             "key": "dept",                      +
             "value": "Engineering",             +
             "values": "Engineering",            +
             "display_name": "Department"        +
         }                                       +
     ]                                           +
 }
(1 row)

Now perform an update:

DO
$BODY$
DECLARE
    record jsonb;
    ind int;
    path text[];
BEGIN
    FOR record IN SELECT data FROM test_table
    LOOP
        FOR ind in 0..(jsonb_array_length(record->'attributes'))
        LOOP
            IF record->'attributes'->ind->>'key' = 'dept'
            THEN
                path = ARRAY['attributes', ind::text, 'value'];
                UPDATE test_table
                    SET data = jsonb_set(data, path, '"Technology"')
                    WHERE data->>'emp_id' = record->>'emp_id';
            END IF;
        END LOOP;
    END LOOP;
END;
$BODY$ language plpgsql;

And here is the result:

=# select jsonb_pretty(data) from test_table;                                                                                                                    
                   jsonb_pretty                   
--------------------------------------------------
 {                                               +
     "name": "Rahul Jain",                       +
     "emp_id": "73347",                          +
     "attributes": [                             +
         {                                       +
             "key": "name",                      +
             "value": "Amay Adams",              +
             "display_name": "Name"              +
         },                                      +
         {                                       +
             "key": "designation",               +
             "value": "Senior Software Engineer",+
             "display_name": "Designation"       +
         },                                      +
         {                                       +
             "key": "location",                  +
             "value": "New Delhi",               +
             "display_name": "Location"          +
         },                                      +
         {                                       +
             "key": "dept",                      +
             "value": "Technology",              +
             "display_name": "Department"        +
         },                                      +
         {                                       +
             "key": "dept",                      +
             "value": "Technology",              +
             "values": "Engineering",            +
             "display_name": "Department"        +
         }                                       +
     ]                                           +
 }
(1 row)

Unfortunately, I'm not aware about performance of this solution.