问题描述
我下面有一个JSONB数组
[
{
"name": "test","age": "21","phone": "6589","town": "54"
},{
"name": "test12","age": "67","phone": "6546",{
"name": "test123",{
"name": "test125","town": "54"
}
]
现在,如果名称为test或test125,我想删除该对象。如何删除JSONB数组中的多个或单个值?
解决方法
一个包含子查询的更新语句,可以使用NOT IN
运算符删除不需要的元素,并使用jsonb_agg()
函数聚合其余元素,从而找出该操作:
选择此:
1. UPDATE tab
SET jsdata = t.js_new
FROM
(
SELECT jsonb_agg( (jsdata ->> ( idx-1 )::int)::jsonb ) AS js_new
FROM tab
CROSS JOIN jsonb_array_elements(jsdata)
WITH ORDINALITY arr(j,idx)
WHERE j->>'name' NOT IN ('test','test125')
) t
或这个:
2. WITH t AS (
SELECT jsonb_agg( (jsdata ->> ( idx-1 )::int)::jsonb ) AS js_new
FROM tab
CROSS JOIN jsonb_array_elements(jsdata)
WITH ORDINALITY arr(j,idx)
WHERE j->>'name' NOT IN ('test','test125')
)
UPDATE tab
SET jsdata = js_new
FROM t
,
如果您拥有Postgres 12,则可以使用jsonb_path_query_array
函数来过滤jsonb
,这是您的问题示例:
with t (j) as ( values ('[
{"name":"test","age":"21","phone":"6589","town":"54"},{"name":"test12","age":"67","phone":"6546",{"name":"test123",{"name":"test125","town":"54"}
]'::jsonb) )
select jsonb_path_query_array(j,'$[*] ? (@.name != "test" && @.name != "test125")')
from t;
有关https://www.postgresql.org/docs/12/functions-json.html的更多信息
,我将创建一个执行该操作的函数:
create function remove_array_elements(p_data jsonb,p_key text,p_value text[])
returns jsonb
as
$$
select jsonb_agg(e order by idx)
from jsonb_array_elements(p_data) with ordinality as t(e,idx)
where t.e ->> p_key <> ALL (p_value) ;
$$
language sql
immutable;
然后您可以像这样使用它:
update the_table
set the_column = remove_array_elements(the_column,'name',array['test','test125'])
where id = ...;