我有一个名为
report
的表,其中包含一个名为 data 的 JSON 类型列。
我想做两件事:
"number"
开头的键并将其值更新为数字123
。例如,记录1
{"number_01": 14322, "number_98": 629578}
将更新为
{"number_01": 123, "number_98": 123}
"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代码代替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