我需要MERGE
两个JSONB_ARRAYS
我的表格列jsonb
中有类似以下内容的项目:
[
{"fav": 1, "is_active": true, "date": "1999-00-00 11:07:05.710000"},
{"fav": 2, "is_active": true, "date": "1998-00-00 11:07:05.710000"}
]
其中fav的值是唯一编号。
我有传入的数据,其中可能是表中也存在的相同项目,还有新项目,合并结果后必须是这样,即只需添加新项目但我需要更新的现有项目>
因此合并后的结果必须如下所示:
merge:
[
{"fav": 1, "is_active": true, "date": "1999-00-00 11:07:05.710000"},
{"fav": 2, "is_active": true, "date": "1998-00-00 11:07:05.710000"}
]::jsonb ||
[
{"fav": 3, "is_active": true, "date": "2019-00-00 11:07:05.710000"},
{"fav": 1, "is_active": false, "date": "2020-00-00 11:07:05.710000"}
]::jsonb
------------------------------------------------------------------------
result:
[
{"fav": 1, "is_active": false, "date": "2020-00-00 11:07:05.710000"},
{"fav": 2, "is_active": true, "date": "1998-00-00 11:07:05.710000"},
{"fav": 3, "is_active": true, "date": "2019-00-00 11:07:05.710000"}
]
如预期的那样,"fav": 1
->已更新,并添加了"fav": 3
->
也许我需要json
的一些修饰结构,也许还有其他东西?
也许如果我将json检索到Collection并使用对象并在所有操作之后将其保存回去会更好?
我尝试编写自定义函数:
CREATE OR REPLACE FUNCTION public.json_array_merge(data1 jsonb, merge_data jsonb)
RETURNS jsonb
IMMUTABLE
LANGUAGE sql
AS $$
SELECT jsonb_agg(expression)::jsonb
FROM (
WITH to_merge AS (
SELECT * FROM jsonb_each(jsonb_array_elements(merge_data))
)
SELECT *
FROM json_each(jsonb_array_elements(data1))
WHERE value NOT IN (SELECT value FROM to_merge)
UNION ALL
SELECT * FROM to_merge
) expression;
$$;
但现在不起作用(
答案 0 :(得分:0)
您可能想编写一个自定义函数来处理此问题。默认行为是附加每个值,因为它无法知道您希望fav
是唯一的。
如果您的数据使用fav作为关键字,例如
{
"fav1": {"date": "2020-00-00 11:07:05.710000", "is_active": false},
"fav2": {"date": "1998-00-00 11:07:05.710000", "is_active": true},
"fav3": {"date": "2019-00-00 11:07:05.710000", "is_active": true}
}
这将很容易管理,但是由于您使用的是数组,因此需要创建一个自定义函数来迭代并检查每个值。
编辑您将需要使用plpgsql运行一些循环,使用plv8可以更有效地实现这一点
CREATE OR REPLACE FUNCTION public.json_array_merge(
data_new jsonb,
data_old jsonb,
key_val text
)
RETURNS jsonb
AS $$
DECLARE
ret jsonb := '[]'::jsonb;
cur text;
add boolean := true;
i integer := 0;
ic integer := jsonb_array_length(data_old);
j integer := 0;
jc integer := jsonb_array_length(data_new);
BEGIN
IF ic > 0 AND jc > 0 THEN
-- populate or replace the records that are already there
WHILE i < ic LOOP
cur := null;
j := 0;
-- loop new array
WHILE j < jc LOOP
IF data_old->i->>key_val = data_new->j->>key_val THEN
cur := data_new->>j;
add := false;
END IF;
j := j + 1;
END LOOP;
-- add or replace
IF add THEN
ret := ret || format('[%s]', data_old->>i)::jsonb;
ELSE
ret := ret || format('[%s]', cur)::jsonb;
END IF;
add := true;
i := i + 1;
END LOOP;
-- loop through the new data again and add any values not in ret
ic := jsonb_array_length(ret);
j := 0;
WHILE j < jc LOOP
i := 0;
add := true;
WHILE i < ic LOOP
IF ret->i->>key_val = data_new->j->>key_val THEN
add := false;
END IF;
i := i + 1;
END LOOP;
IF add THEN
ret := ret || format('[%s]', data_new->>j)::jsonb;
END IF;
j := j + 1;
END LOOP;
ELSE
ret := data_new;
END IF;
RETURN ret;
END
$$
LANGUAGE plpgsql IMMUTABLE;
运行此命令应该会给您想要的结果
SELECT json_array_merge(
'[{"fav": 3, "is_active": true, "date": "2019-00-00 11:07:05.710000"},{"fav": 1, "is_active": false, "date": "2020-00-00 11:07:05.710000"}]',
'[{"fav": 1, "is_active": true, "date": "1999-00-00 11:07:05.710000"},{"fav": 2, "is_active": true, "date": "1998-00-00 11:07:05.710000"}]',
'fav'
)