使用 jsonb_set() 进行条件更新
Conditional update with jsonb_set()
我在 Postgres 11.3 数据库中有一个 table,其中有一个 jsonb
列。
正在尝试更新嵌套数组名称中的所有对象 "iProps"
。
如果路径 {iProps -> value -> rules -> ao -> sc}
是对象,则路径应从对象更新为具有值的字符串
{iProps -> value -> rules -> ao -> sc -> name}
如果路径 {iProps -> value -> rules -> ao -> sc}
不存在,则对象应保持不变。
使用查询测试设置:Fiddle link
想要的结果:
{
"iProps": [
{
"value": {
"rules": [
{
"ao": {
"set": "get"
},
"name": "PRule"
},
{
"ao": {
"sc": "name1"
}
},
{
"ao": {
"sc": "name2"
}
},
{
"ao": {
"sc": "name3"
}
}
]
}
}
]
}
我已经修改了 fiddle 中的查询和链接。有没有人看一下对不对?
一个简单的 CASE
应该有所作为。
UPDATE table_ t
SET value_ = jsonb_set(value_, '{iProps}', sub2.new_prop, false)
FROM (
SELECT id
, jsonb_agg(jsonb_set(prop, '{value, rules}', new_rules, false)
ORDER BY idx1) AS new_prop
FROM (
SELECT t.id, arr1.prop, arr1.idx1
, jsonb_agg(<b>CASE WHEN jsonb_typeof(rule #> '{ao,sc}') = 'object'
THEN jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
ELSE rule
END</b>
ORDER BY idx2) AS new_rules
FROM table_ t
, jsonb_array_elements(value_->'iProps') WITH ORDINALITY arr1(prop,idx1)
, jsonb_array_elements(prop->'value'->'rules') WITH ORDINALITY arr2(rule,idx2)
GROUP BY t.id, arr1.prop, arr1.idx1
) sub1
GROUP BY id
) sub2
WHERE t.id = sub2.id;
db<>fiddle here(Postgres 11!)
为了满足您在更新中添加的第二个过滤器(必须是 对象),请检查 jsonb_typeof()
。
your fiddle 中的查询似乎不必要地复杂 (tl;dr)。此外,它不会保留 数组元素的原始顺序 。如果这实际上无关紧要,请省略 WITH ORDINALITY
和 ORDER BY
并进一步简化:
UPDATE table_ t
SET value_ = jsonb_set(value_, '{iProps}', sub2.new_prop, false)
FROM (
SELECT id
, jsonb_agg(jsonb_set(prop, '{value, rules}', new_rules, false)) AS new_prop
FROM (
SELECT t.id, prop
, jsonb_agg(CASE WHEN jsonb_typeof(rule #> '{ao,sc}') = 'object'
THEN jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
ELSE rule
END) AS new_rules
FROM table_ t
, jsonb_array_elements(value_->'iProps') prop
, jsonb_array_elements(prop->'value'->'rules') rule
GROUP BY t.id, prop
) sub1
GROUP BY id
) sub2
WHERE t.id = sub2.id;
db<>fiddle here
这通常仍会保留数组元素的顺序(与您的原始顺序不同)。只是不能保证两级聚合。
参见:
- PostgreSQL unnest() with element number
我对您之前的相关问题的回答中有更多建议:
我在 Postgres 11.3 数据库中有一个 table,其中有一个 jsonb
列。
正在尝试更新嵌套数组名称中的所有对象 "iProps"
。
如果路径 {iProps -> value -> rules -> ao -> sc}
是对象,则路径应从对象更新为具有值的字符串
{iProps -> value -> rules -> ao -> sc -> name}
如果路径 {iProps -> value -> rules -> ao -> sc}
不存在,则对象应保持不变。
使用查询测试设置:Fiddle link
想要的结果:
{
"iProps": [
{
"value": {
"rules": [
{
"ao": {
"set": "get"
},
"name": "PRule"
},
{
"ao": {
"sc": "name1"
}
},
{
"ao": {
"sc": "name2"
}
},
{
"ao": {
"sc": "name3"
}
}
]
}
}
]
}
我已经修改了 fiddle 中的查询和链接。有没有人看一下对不对?
一个简单的 CASE
应该有所作为。
UPDATE table_ t
SET value_ = jsonb_set(value_, '{iProps}', sub2.new_prop, false)
FROM (
SELECT id
, jsonb_agg(jsonb_set(prop, '{value, rules}', new_rules, false)
ORDER BY idx1) AS new_prop
FROM (
SELECT t.id, arr1.prop, arr1.idx1
, jsonb_agg(<b>CASE WHEN jsonb_typeof(rule #> '{ao,sc}') = 'object'
THEN jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
ELSE rule
END</b>
ORDER BY idx2) AS new_rules
FROM table_ t
, jsonb_array_elements(value_->'iProps') WITH ORDINALITY arr1(prop,idx1)
, jsonb_array_elements(prop->'value'->'rules') WITH ORDINALITY arr2(rule,idx2)
GROUP BY t.id, arr1.prop, arr1.idx1
) sub1
GROUP BY id
) sub2
WHERE t.id = sub2.id;
db<>fiddle here(Postgres 11!)
为了满足您在更新中添加的第二个过滤器(必须是 对象),请检查 jsonb_typeof()
。
your fiddle 中的查询似乎不必要地复杂 (tl;dr)。此外,它不会保留 数组元素的原始顺序 。如果这实际上无关紧要,请省略 WITH ORDINALITY
和 ORDER BY
并进一步简化:
UPDATE table_ t
SET value_ = jsonb_set(value_, '{iProps}', sub2.new_prop, false)
FROM (
SELECT id
, jsonb_agg(jsonb_set(prop, '{value, rules}', new_rules, false)) AS new_prop
FROM (
SELECT t.id, prop
, jsonb_agg(CASE WHEN jsonb_typeof(rule #> '{ao,sc}') = 'object'
THEN jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
ELSE rule
END) AS new_rules
FROM table_ t
, jsonb_array_elements(value_->'iProps') prop
, jsonb_array_elements(prop->'value'->'rules') rule
GROUP BY t.id, prop
) sub1
GROUP BY id
) sub2
WHERE t.id = sub2.id;
db<>fiddle here
这通常仍会保留数组元素的顺序(与您的原始顺序不同)。只是不能保证两级聚合。
参见:
- PostgreSQL unnest() with element number
我对您之前的相关问题的回答中有更多建议: