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

How to delete multiple values in JSONB array Postgresql array object

我下面有一个JSONB数组

[
  {
    "name": "test",
    "age": "21",
    "phone": "6589",
    "town": "54"
  },
  {
    "name": "test12",
    "age": "67",
    "phone": "6546",
    "town": "54"
  },
  {
    "name": "test123",
    "age": "21",
    "phone": "6589",
    "town": "54"
  },
  {
    "name": "test125",
    "age": "67",
    "phone": "6546",
    "town": "54"
  }
]

现在我想删除名称为test 或test125 的对象。如何删除 JSONB 数组中的多个或单个值?

如果你有 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","town":"54"}, 
  {"name":"test123","age":"21","phone":"6589","town":"54"},
  {"name":"test125","age":"67","phone":"6546","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

包含子查询的更新语句,使用 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