英文:
Remove an object from a JSON array
问题
从我的 PostgreSQL 12.8 数据库的表行中,我试图从数组中删除一个对象,但实际上是删除了整个数组中的对象。
settings
列包含以下对象数组:
[
{
"id": 100,
"name": "testOne",
"settings": "settingOne"
},
{
"id": 101,
"name": "testTwo",
"settings": "settingTwo"
}
]
我在 users
表中有三行,其中 settings
列的数据类型为 jsonb
,其中包含对象数组。
我想要删除所有用户中 id
为 101 的对象。我尝试了以下查询:
update users
set settings =
jsonb_set(settings , '{settings}', (settings->'id') - (select distinct position-1 from users, jsonb_array_elements(settings)
with ordinality arr(elem, position) WHERE elem->>'id' = '101')::int)
通过执行上面的查询,它删除了设置中的所有内容。我应该如何修改上面的查询以达到以下结果?
[
{
"id": 100,
"name": "testOne",
"settings": "settingOne"
}
]
英文:
From table rows in my PostgreSQL 12.8 database, I am trying to remove an object from an array, but instead it is deleting whole array of objects from the table.
settings
column holds below array of objects:
[
{
"id": 100,
"name": "testOne",
"settings": "settingOne"
},
{
"id": 101,
"name": testTwo,
"settings": "settingTwo"
},
]
I have three rows in the users
table with the column settings
of type jsonb
that holds an array of objects.
I want to delete the object with id = 101 for all users. I tried the below query:
update users
set settings =
jsonb_set(settings , '{settings}', (settings->'id') - (select distinct position-1 from users, jsonb_array_elements(settings)
with ordinality arr(elem, position) WHERE elem->>'id' = '101')::int)
By executing the above query it is deleting everything from the settings. How can I modify the above query in order to achieve the below result?
[
{
"id": 100,
"name": "testOne"
"settings": "settingOne"
}
]
答案1
得分: 2
这应该可以:
UPDATE users u
SET settings = (SELECT jsonb_agg(a.elem)
FROM jsonb_array_elements(u.settings) AS a(elem)
WHERE (a.elem ->> 'id' = '101') IS NOT TRUE)
WHERE u.settings @> '[{"id":101}]'';
添加的外部 WHERE
子句确保只更新实际发生变化的行。您可以有附加的筛选条件...
这将从数组中删除具有 "id": 101
的所有对象。(可能不止一个。)
要仅删除第一个匹配项:
UPDATE users u
SET settings = u.settings
- (SELECT a.ord::int-1
FROM jsonb_array_elements(u.settings) WITH ORDINALITY a(elem, ord)
WHERE a.elem ->> 'id' = '101'
LIMIT 1)
WHERE u.settings @> '[{"id":101}]'';
请注意,在相关子查询中不要重复表名,这将导致额外的开销 - 并需要额外的筛选条件以链接回更新的表。
-1
是因为Postgres的序号从1开始,而JSON数组元素从0开始。
关于 WITH ORDINALITY
:
英文:
This should do it:
UPDATE users u
SET settings = (SELECT jsonb_agg(a.elem)
FROM jsonb_array_elements(u.settings) AS a(elem)
WHERE (a.elem ->> 'id' = '101') IS NOT TRUE)
WHERE u.settings @> '[{"id":101}]';
The added outer WHERE
clause makes sure only rows are updated that actually change. You may have additional filters ...
This removes all objects from the array that have "id": 101
. (There might be more than one.)
To only remove the first match:
UPDATE users u
SET settings = u.settings
- (SELECT a.ord::int-1
FROM jsonb_array_elements(u.settings) WITH ORDINALITY a(elem, ord)
WHERE a.elem ->> 'id' = '101'
LIMIT 1)
WHERE u.settings @> '[{"id":101}]';
Notably, do not repeat the table name in the correlated subquery, that would be expensive bloat - and require addtitional filters to link back to the updated table.
-1
is there because Postgres ordinality numbers start with 1 while JSON array elements start with 0.
About WITH ORDINALITY
:
答案2
得分: 1
使用operator -,无需使用jsonb_set
。
这是一个经过优化的解决方案,因为它仅调用where
一次。如果未找到数据,它将返回settings length
,这样我们可以确保不会删除任何内容。
update users
set settings =
settings - (
select coalesce(
(select position::int-1 as index
from jsonb_array_elements(settings)
with ordinality arr(elem, position)
WHERE elem->>'id' = '100'
LIMIT 1
),
jsonb_array_length(settings))
)
-
运算符会删除具有指定索引的数组元素(负整数从末尾开始计数)。
英文:
Use operator - only, no need to use jsonb_set
.
This is an optimized solution since it call where
only once. if no data found it will return the settings length
this way we will be sure nothing will be removed.
update users
set settings =
settings - (
select coalesce(
(select position::int-1 as index
from jsonb_array_elements(settings)
with ordinality arr(elem, position)
WHERE elem->>'id' = '100'
LIMIT 1
),
jsonb_array_length(settings))
)
The operator -
Delete the array element with specified index (Negative integers count from the end).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论