在不指定 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
有没有一种方法可以更新数组数组中的 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