在不指定 PostgreSQL 索引的情况下更新数组中的 JSONB 对象

Update JSONB object in array without specifying index in PostgreSQL

有没有一种方法可以更新数组数组中的 JSONB 值而不必指定索引(这并不总是可靠的),而是通过一个对象中的 属性 来更新?

假设我有这个 JSONB 值:

select '[{"foo": [{"id": "baz"}, {"id": "bar"}]}, {"foo": [{"id": "bor"}]}]'::jsonb;

我可以通过以下查询找到 ID 为 bar 的元素:

select * from x where f @> '[{"foo": [{"id": "bar"}]}]'::jsonb:

但我不能只说:更新 ID 为 bar 的对象并在不指定其索引的情况下更改它

UPDATE x SET f = jsonb_set(f, '{0,foo,1}', '{"id": "new-bar", "something": "hello"}'::jsonb);

有没有办法通过使用此嵌套对象的 属性 来更新 JSONB 的一部分而无需指定索引(即位置)?

旁注:索引位置的问题在于它可能因查询而异,并且在读取日志时不可读。

不确定是否足够清楚,如果我可以改进我的问题,请告诉我!

一个选项是将 JSONB_ARRAY_ELEMENTS() 函数与 CROSS JOIN 一起递归地应用到最深的数组元素到达的点。

然后匹配 '{"id": "bar"}::JSONB' 作为搜索标识符:

WITH x0 AS
(
 SELECT j
   FROM x
  CROSS JOIN JSONB_ARRAY_ELEMENTS(f) AS j 
), x1 AS
(
 SELECT ('{foo,'||index-1||'}')::text[] AS path, x0.*
   FROM x0
  CROSS JOIN JSONB_ARRAY_ELEMENTS((j->>'foo')::JSONB) 
   WITH ORDINALITY arr(j1,index)
  WHERE j1 = '{"id": "bar"}'::JSONB   
), x_upd AS
(
SELECT JSONB_AGG(
                 JSONB_SET(x1.j,x1.path,'{"id": "new-bar", "something": "hello"}',false)
       ) AS js_agg
  FROM x1
)
UPDATE x
   SET f = js_agg
  FROM x_upd

Demo