我有如下数据:
id name blocks
1 Test 1 [{"name": "Bob", "type": "INFO", "title": "CFO"}, {"type": "FOOTER"}]
2 Another [{"name": "Bob", "type": "INFO", "title": "Manager"}, {"type": "FOOTER"}]
3 Final [{"id": 22, "type": "IMAGE"}]
用户可能希望在所有行上更改其名称,因此我需要Postgres JSON版本为:
UPDATE blocks SET name = 'New Name' WHERE type = 'INFO';
如何编写查询以在对象的这些数组中搜索值type
的特定"INFO"
键?这里最大的收获是这些对象可以在数组中以任何顺序排列。因此,INFO
块不一定总是位于索引0。
答案 0 :(得分:1)
您的示例中有2个name
字段。
如果要根据您的条件更新name
字段中的json
标记,请尝试以下查询:
with cte as
(
select
id,
name,
json_agg(case when t.x->>'type'='INFO' then jsonb_set(t.x,'{name}','"New Name"',false) else t.x end) "new_value"
from blocks cross join lateral jsonb_array_elements(blocks::jsonb) t(x)
group by 1,2
)
update blocks t1
set blocks=t2.new_value
from cte t2
where t1.id=t2.id;
如果要根据条件更新表的name
字段,请尝试以下查询:
with cte as
(
select
id,
name,
bool_or(t.x->>'type'='INFO') "new_value"
from blocks cross join lateral jsonb_array_elements(blocks::jsonb) t(x)
group by 1,2
)
update blocks t1
set name='New Name'
from cte t2
where t1.id=t2.id and t2.new_value=true;
答案 1 :(得分:1)
这最终是我所用的(基于公认的答案),只是清理了一下,并使用实际的表名和JSONB结构进行了命名。这还可以确保用户只能批量更新自己的数据,而不能批量更新其他人的数据。
WITH new_data AS (
SELECT id, json_agg(
CASE
WHEN blocks.block->>'type' = 'CONTACT_INFO'
THEN jsonb_set(blocks.block, '{data, name}', '"New Name"', false)
ELSE
blocks.block
END) AS new_block
FROM reels
CROSS JOIN LATERAL jsonb_array_elements(blocks) blocks(block)
WHERE owner_id = '9292dcc6-f906-418a-aee0-074b297bfb52'
GROUP BY id
)
UPDATE reels
SET blocks = new_data.new_block
FROM new_data
WHERE reels.id = new_data.id;