[英]Postgres/JSON - update all array elements
Given the following json: 鉴于以下json:
{
"foo": [
{
"bar": true
},
{
"bar": true
}
]
}
How can I select the following: 如何选择以下内容:
{
"foo": [
{
"bar": false
},
{
"bar": false
}
]
}
? ?
So far I've figured out how to manipulate a single array value: 到目前为止,我已经弄清楚如何操作单个数组值:
SELECT
jsonb_set(
'{
"foo": [
{
"bar": true
},
{
"bar": true
}
]
}'::jsonb, '{foo,0,bar}', to_jsonb(false)
)
But how do I set all elements within an array? 但是如何在数组中设置所有元素?
There is no standard function to update json array elements by key. 没有标准函数来按键更新json数组元素。 A custom function is probably the simplest way to solve the problem:
自定义函数可能是解决问题的最简单方法:
create or replace function update_array_elements(arr jsonb, key text, value jsonb)
returns jsonb language sql as $$
select jsonb_agg(jsonb_build_object(k, case when k <> key then v else value end))
from jsonb_array_elements(arr) e(e),
lateral jsonb_each(e) p(k, v)
$$;
select update_array_elements('[{"bar":true},{"bar":true}]'::jsonb, 'bar', 'false');
update_array_elements
----------------------------------
[{"bar": false}, {"bar": false}]
(1 row)
Your query may look like this: 您的查询可能如下所示:
with a_data(js) as (
values(
'{
"foo": [
{
"bar": true
},
{
"bar": true
}
]
}'::jsonb)
)
select
jsonb_set(js, '{foo}', update_array_elements(js->'foo', 'bar', 'false'))
from a_data;
jsonb_set
-------------------------------------------
{"foo": [{"bar": false}, {"bar": false}]}
(1 row)
You might want to kill two birds with one stone - update existing key in every object in the array or insert the key with a given value. 您可能希望一石二鸟 - 更新阵列中每个对象的现有键或插入具有给定值的键。
jsonb_set
is a perfect match here, but it requires us to pass the index of each object, so we have to iterate over the array first. jsonb_set
在这里是一个完美的匹配,但它要求我们传递每个对象的索引,所以我们必须首先迭代数组。
The implementation is HIGHLY inspired by klin's answer, which didn't solve my problem (which was updating and inserting) and didn't work if there were multiple keys in the object. 该实现受到了klin的答案的启发,它没有解决我的问题(更新和插入),如果对象中有多个键,则无法正常工作。 So, the implementation is as follows:
所以,实施如下:
-- the params are the same as in aforementioned `jsonb_set`
CREATE OR REPLACE FUNCTION update_array_elements(target jsonb, path text[], new_value jsonb)
RETURNS jsonb language sql AS $$
-- aggregate the jsonb from parts created in LATERAL
SELECT jsonb_agg(updated_jsonb)
-- split the target array to individual objects...
FROM jsonb_array_elements(target) individual_object,
-- operate on each object and apply jsonb_set to it. The results are aggregated in SELECT
LATERAL jsonb_set(individual_object, path, new_value) updated_jsonb
$$;
And that's it... :) 就是这样...... :)
I hope it'll help someone with the same problem I had. 我希望它能帮助那些遇到同样问题的人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.