如何替换以短语开头的键下的 JSON 值

问题描述 投票:0回答:1

我有一个名为

report
的表,其中包含一个名为 data 的 JSON 类型列。 我想做两件事:

  1. 找到以
    "number"
    开头的键并将其值更新为数字
    123
    。例如,记录1
    {"number_01": 14322, "number_98": 629578}
    
    将更新为
    {"number_01": 123, "number_98": 123}
    
  2. 找到包含
    "http://139.168.6.44"
    的值,无论键的名称是什么,并将值替换为
    "http://139.168.6.55"
    。例如,记录1
    {file: "http://139.168.6.44/upload"} 
    
    将被替换为
    {file: "http://139.168.6.55/upload"}
    

此外,我事先并不知道数据结构,以

"number"
开头的字段可以位于任何嵌套级别。

我尝试运行代码来更新数值,但它不起作用,代码运行了很长时间

DO $$
    DECLARE
      _keys_to_update TEXT[];
      _key TEXT;
    BEGIN
      SELECT ARRAY(
        SELECT j.key
        FROM report,
          LATERAL jsonb_each(data) AS j (key, _)
        WHERE j.key LIKE 'number%'
      ) INTO _keys_to_update;
       
      FOREACH _key IN ARRAY _keys_to_update 
        LOOP
         UPDATE report
       SET data = jsonb_set(data, ARRAY[_key], to_jsonb(123));   
      END LOOP;
END $$;
sql postgresql plpgsql jsonb
1个回答
0
投票

你可以使用sql代码代替plpgsql,它会运行得更快。试试这个:

CREATE FUNCTION jsonb_update (input jsonb) RETURNS jsonb LANGUAGE sql AS
$$
  SELECT json_objectagg
            ( j.key :: text : 
              CASE 
                WHEN jsonb_typeof(j.value) = 'object' THEN jsonb_update(j.value)
                WHEN j.key :: text ~ '^number' THEN to_jsonb(123)
                WHEN j.value :: text ~ '^"http:// 139.168.6.44' THEN to_jsonb(replace (j.value :: text, 'http:// 139.168.6.44', 'http:// 139.168.6.55'))
                ELSE j.value
              END
            )
    FROM jsonb_each(input) AS j(key,value) ;
$$ ;

然后运行查询:

SELECT jsonb_update('{"number_01":14322,"number_98":629578,"file":"http:// 139.168.6.44/upload", "nested_object":{"number_01":14322,"number_98":629578,"file":"http:// 139.168.6.44/upload"}}' :: jsonb)

你得到了结果:

{"file": ""http:// 139.168.6.55/upload"", "number_01": 123, "number_98": 123, "nested_object": {"file": ""http:// 139.168.6.55/upload"", "number_01": 123, "number_98": 123}}

参见dbfiddle

© www.soinside.com 2019 - 2024. All rights reserved.