在一个 postgresql 语句中删除多个 key/value 对

Remove multiple key/value pairs in one postgresql statement

伙计们!我的 table 模板只有 1 列来自 JSON 类型。 专栏

{
    "name": "any name",
    "headers": {
        "Accept": ["application/json"],
        "ApiSecret": ["keySecret==="],
        "ApiSecretKey": ["key==="],
        "X-Auth-Token": ["token=="],
        "OAUTH-Token": ["token2=="],
        "Authorization": ["basicAuth"]
                },
    "description": "any desc"
}

我必须删除所有 headers,例如 %authorization%、%token%、%apiSecret%。

我创建了以下查询:

UPDATE template as w
SET 
    column = column::jsonb - ARRAY(select wf.elements
from (select jsonb_object_keys(column->'headers') as elements
    from template) as wf
where LOWER(wf.elements) LIKE ANY(ARRAY['%authorization%','%token%','%apikey%'])); 

很遗憾,我的查询不起作用。问题出在哪里?

(a) 您不能将 jsonb 类型与数组类型混合使用:column::jsonb - ARRAY(...) 是不允许的。

(b) 如果你想从同一个jsonb数据中删除几个key/value对,那么你必须创建一个基于jsonb #-运算符的user-defined aggregate :

CREATE OR REPLACE FUNCTION jsonb_remove(x jsonb, y jsonb, p text[])
RETURNS jsonb LANGUAGE sql IMMUTABLE AS
$$  SELECT COALESCE(x, y) #- p ; $$ ;

DROP AGGREGATE IF EXISTS jsonb_remove_agg(jsonb, text[]) ;
CREATE AGGREGATE jsonb_remove_agg(jsonb, text[])
( sfunc = jsonb_remove
, stype = jsonb
) ;

然后您可以在查询中迭代新聚合:

UPDATE template as w
SET 
    column = l.elements
FROM
   ( SELECT id -- id is to be replaced by the primary key of table template
          , jsonb_remove_agg(column, array['headers', wf.elements]) as elements
       FROM template
      CROSS JOIN LATERAL jsonb_object_keys(column->'headers') as wf(elements)
      WHERE LOWER(wf.elements) LIKE ANY(ARRAY['%authorization%','%token%','%apikey%'])
     GROUP BY id -- id is to be replaced by the primary key of table template
   ) AS l
WHERE w.id = l.id ; -- -- id is to be replaced by the primary key of table template

查看dbfiddle中的测试结果。