如何更新JSONB以将所有记录的新键添加到嵌套数组(对于数组的所有项目)中。
我指的是link 表结构为:
CREATE TABLE orders (
id serial PRIMARY KEY,
data jsonb
);
给定的json是:
{
"Number": "555",
"UserId": "1",
"Items": [
{
"ProductId": "1",
"Name": "TV",
"Price": "300.00"
},
{
"ProductId": "2",
"Name": "Mechanical Keyboard",
"Price": "120.00"
}
]
}
要向每个数组项中添加新元素,请执行以下查询:
UPDATE orders
SET data = jsonb_set(
data,
'{Items}', -- the array in which we operate
to_jsonb(
(WITH ar AS(
WITH temp AS(
SELECT data->'Items' AS items -- the array in which we operate
FROM orders
WHERE id = 1 -- the filtered order we are updating
)
SELECT jsonb_set(
jsonb_array_elements(items),
'{Quantity}', -- the new field we are adding
'"1"', -- the value of the new field
true)
FROM temp)
SELECT (array_agg(ar.jsonb_set))
FROM ar)),
false)
WHERE id = 1;
执行上述查询后的输出:
{
"Number": "555",
"UserId": "1",
"Items": [
{
"ProductId": "1",
"Name": "TV",
"Price": "300.00",
"Quantity": "1"
},
{
"ProductId": "2",
"Name": "Mechanical Keyboard",
"Price": "120.00",
"Quantity": "1"
}
]
}
但是上面只会在id=1
处更新json。对于订单中的所有行,更新与上面相同的JSON需要进行哪些更改?
答案 0 :(得分:1)
一个一般性提示,如果您必须修改嵌套的JSON元素,则这是一个严重的信号,表明可以更好地设计数据模型。但是,如果您别无选择,请使用辅助功能。它使事情变得更简单,代码更易读和调试。
create or replace function jsonb_insert_into_elements(jsonb, jsonb)
returns jsonb language sql immutable as $$
select jsonb_agg(value || $2)
from jsonb_array_elements($1)
$$;
现在更新非常简单而优雅:
update orders
set data = jsonb_set(
data,
'{Items}',
jsonb_insert_into_elements(data->'Items', '{"Quantity": "1"}'))
where id = 1 -- just skip this if you want to update all rows
答案 1 :(得分:1)
您无需在SELECT data->'Items' AS items FROM orders WHERE id = 1
语句中进行SET
CTE的操作-您只需直接引用data->'Items'
,它就会占用当前更新的行,就像您已经在data = jsonb_set(data, …)
中执行。因此,您可以简化为
UPDATE orders
SET data = jsonb_set(
data,
'{Items}', -- the array in which we operate
(SELECT jsonb_agg(jsonb_set(
item,
'{Quantity}', -- the new field we are adding
'"1"', -- the value of the new field
true))
FROM jsonb_array_elements(data->'Items')) AS item, -- the array in which we operate
false)
WHERE id = 1;
(我也摆脱了其他CTE,并用to_jsonb(array_agg(…))
取代了jsonb_agg
)
现在,更新所有行所需要做的就是省略WHERE
子句。