如何删除JSONB数组Postgresql数组对象中的多个值

问题描述

我下面有一个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

Demo

,

如果您拥有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 = ...;

Online example