通过 id 更新 Postgres 9.5 Jsonb
Updating Postgres 9.5 Jsonb by id
我已经阅读了文档和堆栈,但我太笨了,无法在不问我的具体问题的情况下得到这个。
假设我有一个对象数组存储在 jsonb 列中,例如
[{"id":1, "value":"a"], {"id":2, "value":"b"}]
如果您没有索引并且必须按 id=2 搜索,将索引 1 的值从 "b" 更改为 "c" 的最有效方法是什么?
更具体地说,我正在编写一个 react/redux/node 实时应用程序,我不想信任 redux 状态来为索引提供更新值。相反,我希望客户端发送 id=2 并让 server/database 找到该数组的索引,然后更新值。
我目前正在使用 return 索引的逻辑(例如 select 整个 jsonb 列,使用 lodash 函数查找 id=2 的索引,然后更新 jsonb_set 与 lodash 找到的索引)。
我希望有一个查询,没有服务器逻辑方式来完成这个。我试过使用子查询,但 postgres 文档没有说明如何 return 索引。
感谢您的帮助!
编辑:这是当前使用 Node.js 的数据库查询和逻辑。
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 查询吗?
示例数据:
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)
我已经阅读了文档和堆栈,但我太笨了,无法在不问我的具体问题的情况下得到这个。
假设我有一个对象数组存储在 jsonb 列中,例如
[{"id":1, "value":"a"], {"id":2, "value":"b"}]
如果您没有索引并且必须按 id=2 搜索,将索引 1 的值从 "b" 更改为 "c" 的最有效方法是什么?
更具体地说,我正在编写一个 react/redux/node 实时应用程序,我不想信任 redux 状态来为索引提供更新值。相反,我希望客户端发送 id=2 并让 server/database 找到该数组的索引,然后更新值。
我目前正在使用 return 索引的逻辑(例如 select 整个 jsonb 列,使用 lodash 函数查找 id=2 的索引,然后更新 jsonb_set 与 lodash 找到的索引)。
我希望有一个查询,没有服务器逻辑方式来完成这个。我试过使用子查询,但 postgres 文档没有说明如何 return 索引。
感谢您的帮助!
编辑:这是当前使用 Node.js 的数据库查询和逻辑。
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 查询吗?
示例数据:
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)