使用 jsonb_set() 更新仅影响嵌套数组中的一个对象
UPDATE with jsonb_set() only affects one object in nested array
试图更新 jsonb
列中嵌套数组的所有元素,但只有一个元素被更新。我的查询:
update table_
set value_ = jsonb_set(value_,cte.json_path,cte.namevalue,false) FROM (
select
vals2->'ao'->'sc'->'name' as namevalue,
('{iProps,'||index1-1||',value,rules,'||index2-1||',ao,sc}')::text[] as json_path
from
table_,
jsonb_array_elements(value_->'iProps')
with ordinality arr1(vals1,index1),
jsonb_array_elements(vals1->'value'->'rules')
with ordinality arr2(vals2,index2)
) AS cte;
查看带有示例值的演示:
db<>fiddle here
无法理解为什么此查询会更新 rules
数组中的第一个对象:
iProps -> value -> rules -> ao -> sc -> name = "name1"
但不是后续的:
iProps -> value -> rules -> ao -> sc -> name = "name2"
iProps -> value -> rules -> ao -> sc -> name = "name3"
说明
您的 UPDATE
returns 三个 行的 FROM
子句中的子选择。但是目标 table 中的每一行只能在单个 UPDATE
命令中更新 一次 。结果是您只能看到这三行中 一个 的效果。
或者,用the manual的话来说:
When using FROM
you should ensure that the join produces at most one
output row for each row to be modified. In other words, a target row
shouldn't join to more than one row from the other table(s). If it
does, then only one of the join rows will be used to update the target
row, but which one will be used is not readily predictable.
旁白:不要将子查询称为“cte”。这不是 Common Table Expression.
正确的UPDATE
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(jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
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
在将每个对象(数组元素)聚合回数组之前,对它们使用 jsonb_set()
。首先在叶级别,然后在更深的级别。
我将 id
添加为 PRIMARY KEY
到 table。我们需要一些唯一的列来分隔行。
添加的 ORDER BY
可能需要也可能不需要。添加它以保证原始订单。
当然,如果您的数据与示例一样规则,则具有专用列的关系设计可能是更简单的替代方案。参见
- How to perform update operations on columns of type JSONB in Postgres 9.4
试图更新 jsonb
列中嵌套数组的所有元素,但只有一个元素被更新。我的查询:
update table_
set value_ = jsonb_set(value_,cte.json_path,cte.namevalue,false) FROM (
select
vals2->'ao'->'sc'->'name' as namevalue,
('{iProps,'||index1-1||',value,rules,'||index2-1||',ao,sc}')::text[] as json_path
from
table_,
jsonb_array_elements(value_->'iProps')
with ordinality arr1(vals1,index1),
jsonb_array_elements(vals1->'value'->'rules')
with ordinality arr2(vals2,index2)
) AS cte;
查看带有示例值的演示:
db<>fiddle here
无法理解为什么此查询会更新 rules
数组中的第一个对象:
iProps -> value -> rules -> ao -> sc -> name = "name1"
但不是后续的:
iProps -> value -> rules -> ao -> sc -> name = "name2"
iProps -> value -> rules -> ao -> sc -> name = "name3"
说明
您的 UPDATE
returns 三个 行的 FROM
子句中的子选择。但是目标 table 中的每一行只能在单个 UPDATE
命令中更新 一次 。结果是您只能看到这三行中 一个 的效果。
或者,用the manual的话来说:
When using
FROM
you should ensure that the join produces at most one output row for each row to be modified. In other words, a target row shouldn't join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable.
旁白:不要将子查询称为“cte”。这不是 Common Table Expression.
正确的UPDATE
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(jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
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
在将每个对象(数组元素)聚合回数组之前,对它们使用 jsonb_set()
。首先在叶级别,然后在更深的级别。
我将 id
添加为 PRIMARY KEY
到 table。我们需要一些唯一的列来分隔行。
添加的 ORDER BY
可能需要也可能不需要。添加它以保证原始订单。
当然,如果您的数据与示例一样规则,则具有专用列的关系设计可能是更简单的替代方案。参见
- How to perform update operations on columns of type JSONB in Postgres 9.4