使用 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