我已经阅读了文档和堆栈,但是如果不问我的具体问题,我就太傻了。
假设我有一个存储在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查询吗?
答案 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)