PostgreSQL 11+
如果您已经在使用 PostgreSQL v. 11(因为 new JSONB type conversion support),您最好的选择可能是使用 Perl 或 Python 编写的自定义函数。
因为我更喜欢 Python 3,所以这里有一个功能示例:
CREATE OR REPLACE FUNCTION jsonb_replace_in_array (val jsonb, path_to_array text[], replacement jsonb, entry_filters jsonb)
RETURNS jsonb
TRANSFORM FOR TYPE jsonb
LANGUAGE plpython3u
AS $$
v_new = val
tmp = v_new
for e in path_to_array:
tmp = tmp[e]
for item in tmp:
if (entry_filters is None or entry_filters.items() <= item.items()):
item.update(replacement)
return v_new
$$;
...然后可以如下使用:
UPDATE configuration
SET
config = jsonb_replace_in_array(
config,
'{data}',
'{"value":"changed"}'::jsonb,
'{"oid":"11.5.15.1.4","instance":"1.1.4"}'::jsonb
)
WHERE config->'data' @> '[{"oid":"11.5.15.1.4","instance":"1.1.4"}]';
所以是的,条件是重复的,但只是为了首先限制要触摸的行数。
要在简单的 PostgreSQL 11 安装中实际工作,您需要扩展 plpython3u 和 jsonb_plpython3u:
CREATE EXTENSION plpython3u;
CREATE EXTENSION jsonb_plpython3u;
Python 逻辑解释:
for e in path_to_array:
tmp = tmp[e]
...让我们找到需要查看的条目数组。
for item in tmp:
if (entry_filters is None or entry_filters.items() <= item.items()):
item.update(replacement)
...对于数组中的每个项目,我们检查过滤条件是否为null(entry_filters is None = 匹配任何条目)或条目是否“包含”提供的示例,包括键和值(entry_filters.items() <= item.items() )。
如果 en 条目匹配,则使用提供的替换覆盖/添加内容。
我希望这会朝着你寻找的方向发展。
查看 PostgreSQL 与 JSON 修改相关的当前功能,这将是非常复杂的(如果不复杂的话)并且会引入大量开销来使用纯 SQL 进行相同操作。
PostgreSQL 9.6+
如果您还没有可用的版本 11,以下函数将执行相同的操作,但会自行处理类型转换,但要保持完全与 API 兼容,因此一旦升级,您唯一要做的就是所要做的就是替换函数(无需更改使用此函数的任何语句):
CREATE OR REPLACE FUNCTION jsonb_replace_in_array (val jsonb, path_to_array text[], replacement jsonb, entry_filters jsonb)
RETURNS jsonb
LANGUAGE plpython3u
AS $$
import json
v_new = json.loads(val)
t_replace = json.loads(replacement)
t_filters = json.loads(entry_filters)
tmp = v_new
for e in path_to_array:
tmp = tmp[e]
for item in tmp:
if (entry_filters is None or t_filters.items() <= item.items()):
item.update(t_replace)
return json.dumps(v_new)
$$;