我在PostgreSQL中获得了以下jsonb
内容:
{
"segments": [
{
"type": "year",
"settings": [
{
"name": "length",
"value": "4"
}
]
},
{
"type": "month",
"settings": [
{
"name": "length",
"value": "2"
}
]
},
{
"type": "dayOfMonth",
"settings": [
{
"name": "length",
"value": "2"
}
]
},
{
"type": "autoIncrement",
"settings": [
{
"name": "scope",
"value": "plant"
},
{
"name": "period",
"value": "day"
},
{
"name": "length",
"value": "10"
},
{
"name": "paddingCharactor",
"value": "0"
}
]
}
]
}
我想在 segments-> type = autoIncrement-> settings-> period
中将“ day”的时间更新为“ forever”我尝试过jsonb_set
并在拆分后手动合并数据,但都失败了。
有什么想法更新值吗?
答案 0 :(得分:0)
尽管对于高度不可读的查询来说,这是可能的,但PostgreSQL jsonb_set
函数尚不能利用JSONPath来选择要替换的元素,但是有work in-progress与{{3} }。
暂时最好编写一个辅助函数。
我更喜欢Python,这是我的看法(通用性足以支持不同的场景,但经过量身定制又不会变得不可用):
CREATE OR REPLACE FUNCTION jsonb_change_setting(val jsonb, segment_filter jsonb, setting text, replacement jsonb)
RETURNS jsonb
TRANSFORM FOR TYPE jsonb
LANGUAGE plpython3u
AS $$
v_new = val
tmp = v_new["segments"]
for item in tmp:
if (segment_filter.items() <= item.items()):
settings = item["settings"]
for s in settings:
if (s["name"] == setting):
s["value"] = replacement
return v_new
$$;
...并且可以根据需要按以下方式调用:
UPDATE serial_rules
SET rule = jsonb_change_setting(config, '{"type":"autoIncrement"}', 'period', '"forever"')
WHERE ...
请注意,此功能需要PostgreSQL 11以及扩展名plpython3u和jsonb_plpython3u(用于jsonb的自动处理)。
PostgreSQL 9.6+的版本(其中jsonb_plpython3u
类型转换器扩展不可用)将是:
CREATE OR REPLACE FUNCTION jsonb_change_setting(val jsonb, segment_filter jsonb, setting text, replacement jsonb)
RETURNS jsonb
LANGUAGE plpython3u
AS $$
import json
v_new = json.loads(val)
tmp = v_new["segments"]
for item in tmp:
if (segment_filter.items() <= item.items()):
settings = item["settings"]
for s in settings:
if (s["name"] == setting):
s["value"] = replacement
return json.dumps(v_new)
$$;
答案 1 :(得分:0)
要根据请求更新给定的jsonb
值:
WITH cte(j) AS (
SELECT jsonb '{ ... }'
)
SELECT jsonb_set(j, '{segments,-1,settings,1,value}'::text[], '"forever"')
FROM cte;
db <>提琴here
但是我不确定您是否一直在问正确的问题。
困难的部分是要知道每个嵌套数组中的数组位置。我采用了外部数组的最后一个元素(-1
)和内部数组的第二个元素(1
)。这是使用纯SQL使其完全动态的方法:
请考虑使用标准化设计like Kaushik suggested。
答案 2 :(得分:0)
感谢您的回答,最终的解决方案是将json内容转换为文本后直接替换为jsonb,然后直接替换。
问题在于如何检测哪个元素是要在数组中更新的正确元素,并且单个结构具有两层数组。因此,我认为替换其内容的最佳方法是使用替换功能。