通过id更新Postgres 9.5 Jsonb

时间:2016-05-12 17:55:52

标签: json postgresql jsonb postgresql-9.5

我已经阅读了文档和堆栈,但是如果不问我的具体问题,我就太傻了。

假设我有一个存储在jsonb列中的对象数组,例如

[{"id":1, "value":"a"], {"id":2, "value":"b"}]

从" b"更改索引1的值的最有效方法是什么?到" c"如果你没有索引,必须按id = 2搜索?

更具体地说,我正在编写react / redux / node实时应用程序,我不想信任redux状态以给索引更新值。相反,我希望客户端发送id = 2并让服务器/数据库找到该数组的索引,然后更新该值。

我目前正在使用逻辑来返回索引(例如,选择整个jsonb列,使用lodash函数查找id = 2的索引,然后使用lodash found索引更新jsonb_set)。

我希望有一个查询,没有服务器逻辑方法来完成此任务。我尝试使用子查询,但postgres文档没有显示如何返回索引。

感谢您的帮助!

编辑:这是使用Node的当前数据库查询和逻辑。

let _ = require('lodash');
let id=2;
let newValue='c';
let query=`SELECT jsonb_column from table where rowid=1`;
pgQuery(query)
.then((result)=>{
    result=result[0].result // cleaning up the return object
    //result=[{"id":1, "value":"a"], {"id":2, "value":"b"}];
    let index=_.findLastIndex(result, {id}) // index=1
    let query2=`UPDATE table
               SET jsonb_column=jsonb_set(jsonb_column, '{${index}, value}', '${newValue}') 
               WHERE rowid=1` RETURNING jsonb_column

    return pgQuery(query2) 
    // returns [{"id":1, "value":"a"], {"id":2, "value":"c"}];
})

可以减少到一个postgres查询吗?

1 个答案:

答案 0 :(得分:3)

示例数据:

create table a_table (rowid int, jsonb_column jsonb);
insert into a_table values (1, '[{"id":1, "value":"a"}, {"id":2, "value":"b"}]');
insert into a_table values (2, '[{"id":2, "value":"a"}, {"id":1, "value":"b"}]');

您有两种选择。第一个(有点复杂),使用jsonb_array_elements(jsonb_column) with ordinality

update a_table t1
set jsonb_column = 
        jsonb_set(
            jsonb_column, 
            array[(
                select ordinality::int- 1
                from a_table t2, jsonb_array_elements(jsonb_column) with ordinality
                where t1.rowid = t2.rowid and value->>'id' = '2')::text,
            'value'::text],
            '"c"'
        );

select * from a_table;

 rowid |                    jsonb_column                    
-------+----------------------------------------------------
     1 | [{"id": 1, "value": "a"}, {"id": 2, "value": "c"}]
     2 | [{"id": 2, "value": "c"}, {"id": 1, "value": "b"}]
(2 rows)

第二个选项(稍微简单一些),修改连续json元素中的值并聚合结果:

update a_table t1
set jsonb_column = (
    select jsonb_agg(val)
    from (
        select case 
            when value->'id' = '2' then jsonb_set(value, '{value}', '"d"')
            else value end val
        from a_table t2, jsonb_array_elements(jsonb_column)
        where t1.rowid = t2.rowid
        ) s
    );

select * from a_table;

 rowid |                    jsonb_column                    
-------+----------------------------------------------------
     1 | [{"id": 1, "value": "a"}, {"id": 2, "value": "d"}]
     2 | [{"id": 2, "value": "d"}, {"id": 1, "value": "b"}]
(2 rows)