如何从 Postgres 中所有 table 行的 JSONB 数组中删除节点?
How to delete a node from a JSONB Array across all table rows in Postges?
我有一个名为“书签”的 table,其中包含多个标准行和一个名为“columnsettings”的 JSONB 列
此 JSONB 列的内容如下所示。
[
{
"data": "id",
"width": 25
},
{
"data": "field_1",
"width": 125
},
{
"data": "field_12",
"width": 125
},
{
"data": "field_11",
"width": 125
},
{
"data": "field_2",
"width": 125
},
{
"data": "field_7",
"width": 125
},
{
"data": "field_8",
"width": 125
},
{
"data": "field_9",
"width": 125
},
{
"data": "field_10",
"width": 125
}
]
我正在尝试编写一个更新语句,该语句将通过删除我指定的特定节点来更新此列设置。例如,我可能想更新列设置并仅删除 data='field_2' 作为示例的节点。
我已经尝试了很多东西...我相信它看起来像这样,但这是错误的。
update public."Bookmarks"
set columnsettings =
jsonb_set(columnsettings, (columnsettings->'data') - 'field_2');
像这样在 JSONB 数组中删除节点的正确语法是什么?
当只有一行时,我确实得到了一个版本。这会正确更新 JSONB 列并删除节点
UPDATE public."Bookmarks" SET columnsettings = columnsettings - (select position-1 from public."Bookmarks", jsonb_array_elements(columnsettings) with ordinality arr(elem, position) WHERE elem->>'data' = 'field_2')::int
但是,我希望它应用于 table 中的每一行。当多于 1 行时,出现错误“用作表达式的子查询返回多于一行”
如何让这个查询更新 table 中的所有行?
已更新,提供的答案解决了我的问题。
我现在有另一个 JSONB 列,我需要在其中进行相同的过滤。结构有点不同,看起来像这样
{
"filters": [
{
"field": "field_8",
"value": [
1
],
"header": "Colors",
"uitype": 7,
"operator": "searchvalues",
"textvalues": [
"Red"
],
"displayfield": "field_8_options"
}
],
"rowHeight": 1,
"detailViewWidth": 1059
}
我尝试使用如下相同的语法:
UPDATE public."Bookmarks"
SET tabsettings = filtered_elements.tabsettings
FROM (
SELECT bookmarkid, JSONB_AGG(el) as tabsettings
FROM public."Bookmarks",
JSONB_ARRAY_ELEMENTS(tabsettings) AS el
WHERE el->'filters'->>'field' != 'field_8'
GROUP BY bookmarkid
) AS filtered_elements
WHERE filtered_elements.bookmarkid = public."Bookmarks".bookmarkid;
这给出了一个错误:“无法从对象中提取元素”
我以为我的语法是正确的,但是应该如何格式化这一行?
WHERE el->'filters'->>'field' != 'field_8'
我也尝试过这种格式来获取数组。这没有给出错误,但它没有找到任何匹配项......即使有记录。
UPDATE public."Bookmarks"
SET tabsettings = filtered_elements.tabsettings
FROM (
SELECT bookmarkid, JSONB_AGG(el) as tabsettings
FROM public."Bookmarks",
JSONB_ARRAY_ELEMENTS(tabsettings->'filters') AS el
WHERE el->>'field' != 'field_8'
GROUP BY bookmarkid
) AS filtered_elements
WHERE filtered_elements.bookmarkid = public."Bookmarks".bookmarkid;
已更新。
如果数组中有多个“过滤器”,则此查询现在似乎可以工作。
但是,如果数组中只有 1 个元素应该被排除,它不会删除该项目。
UPDATE public."Bookmarks"
SET tabsettings = filtered_elements.tabsettings
FROM (
SELECT bookmarkid,
tabsettings || JSONB_BUILD_OBJECT('filters', JSONB_AGG(el)) as tabsettings
FROM public."Bookmarks",
-- this must be an array
JSONB_ARRAY_ELEMENTS(tabsettings->'filters') AS el
WHERE el->>'field' != 'field_8'
GROUP BY bookmarkid
) AS filtered_elements
WHERE filtered_elements.bookmarkid = public."Bookmarks".bookmarkid;
您可以解构、过滤和重新构造 JSONB 数组。这样的事情应该有效:
UPDATE bookmarks
SET columnsettings = filtered_elements.columnsettings
FROM (
SELECT id, JSONB_AGG(el) as columnsettings
FROM bookmarks,
JSONB_ARRAY_ELEMENTS(columnsettings) AS el
WHERE el->>'data' != 'field_2'
GROUP BY id
) AS filtered_elements
WHERE filtered_elements.id = bookmarks.id;
使用 JSONB_ARRAY_ELEMENTS
,您将 JSONB 数组转换为行,每个对象一行,您称之为 el
。然后您可以访问 data
属性以过滤掉“field_2”条目。最后,您按 id
分组,将剩余的值放回一起,并更新相应的行。
编辑 如果您的数据是对象中的嵌套数组,override the object on the specific key:
UPDATE bookmarks
SET tabsettings = filtered_elements.tabsettings
FROM (
SELECT id,
tabsettings || JSONB_BUILD_OBJECT('filters', JSONB_AGG(el)) as tabsettings
FROM bookmarks,
-- this must be an array
JSONB_ARRAY_ELEMENTS(tabsettings->'filters') AS el
WHERE el->>'field' != 'field_2'
GROUP BY id
) AS filtered_elements
WHERE filtered_elements.id = bookmarks.id;
我有一个名为“书签”的 table,其中包含多个标准行和一个名为“columnsettings”的 JSONB 列
此 JSONB 列的内容如下所示。
[
{
"data": "id",
"width": 25
},
{
"data": "field_1",
"width": 125
},
{
"data": "field_12",
"width": 125
},
{
"data": "field_11",
"width": 125
},
{
"data": "field_2",
"width": 125
},
{
"data": "field_7",
"width": 125
},
{
"data": "field_8",
"width": 125
},
{
"data": "field_9",
"width": 125
},
{
"data": "field_10",
"width": 125
}
]
我正在尝试编写一个更新语句,该语句将通过删除我指定的特定节点来更新此列设置。例如,我可能想更新列设置并仅删除 data='field_2' 作为示例的节点。
我已经尝试了很多东西...我相信它看起来像这样,但这是错误的。
update public."Bookmarks"
set columnsettings =
jsonb_set(columnsettings, (columnsettings->'data') - 'field_2');
像这样在 JSONB 数组中删除节点的正确语法是什么?
当只有一行时,我确实得到了一个版本。这会正确更新 JSONB 列并删除节点
UPDATE public."Bookmarks" SET columnsettings = columnsettings - (select position-1 from public."Bookmarks", jsonb_array_elements(columnsettings) with ordinality arr(elem, position) WHERE elem->>'data' = 'field_2')::int
但是,我希望它应用于 table 中的每一行。当多于 1 行时,出现错误“用作表达式的子查询返回多于一行”
如何让这个查询更新 table 中的所有行?
已更新,提供的答案解决了我的问题。
我现在有另一个 JSONB 列,我需要在其中进行相同的过滤。结构有点不同,看起来像这样
{
"filters": [
{
"field": "field_8",
"value": [
1
],
"header": "Colors",
"uitype": 7,
"operator": "searchvalues",
"textvalues": [
"Red"
],
"displayfield": "field_8_options"
}
],
"rowHeight": 1,
"detailViewWidth": 1059
}
我尝试使用如下相同的语法:
UPDATE public."Bookmarks"
SET tabsettings = filtered_elements.tabsettings
FROM (
SELECT bookmarkid, JSONB_AGG(el) as tabsettings
FROM public."Bookmarks",
JSONB_ARRAY_ELEMENTS(tabsettings) AS el
WHERE el->'filters'->>'field' != 'field_8'
GROUP BY bookmarkid
) AS filtered_elements
WHERE filtered_elements.bookmarkid = public."Bookmarks".bookmarkid;
这给出了一个错误:“无法从对象中提取元素”
我以为我的语法是正确的,但是应该如何格式化这一行?
WHERE el->'filters'->>'field' != 'field_8'
我也尝试过这种格式来获取数组。这没有给出错误,但它没有找到任何匹配项......即使有记录。
UPDATE public."Bookmarks"
SET tabsettings = filtered_elements.tabsettings
FROM (
SELECT bookmarkid, JSONB_AGG(el) as tabsettings
FROM public."Bookmarks",
JSONB_ARRAY_ELEMENTS(tabsettings->'filters') AS el
WHERE el->>'field' != 'field_8'
GROUP BY bookmarkid
) AS filtered_elements
WHERE filtered_elements.bookmarkid = public."Bookmarks".bookmarkid;
已更新。
如果数组中有多个“过滤器”,则此查询现在似乎可以工作。 但是,如果数组中只有 1 个元素应该被排除,它不会删除该项目。
UPDATE public."Bookmarks"
SET tabsettings = filtered_elements.tabsettings
FROM (
SELECT bookmarkid,
tabsettings || JSONB_BUILD_OBJECT('filters', JSONB_AGG(el)) as tabsettings
FROM public."Bookmarks",
-- this must be an array
JSONB_ARRAY_ELEMENTS(tabsettings->'filters') AS el
WHERE el->>'field' != 'field_8'
GROUP BY bookmarkid
) AS filtered_elements
WHERE filtered_elements.bookmarkid = public."Bookmarks".bookmarkid;
您可以解构、过滤和重新构造 JSONB 数组。这样的事情应该有效:
UPDATE bookmarks
SET columnsettings = filtered_elements.columnsettings
FROM (
SELECT id, JSONB_AGG(el) as columnsettings
FROM bookmarks,
JSONB_ARRAY_ELEMENTS(columnsettings) AS el
WHERE el->>'data' != 'field_2'
GROUP BY id
) AS filtered_elements
WHERE filtered_elements.id = bookmarks.id;
使用 JSONB_ARRAY_ELEMENTS
,您将 JSONB 数组转换为行,每个对象一行,您称之为 el
。然后您可以访问 data
属性以过滤掉“field_2”条目。最后,您按 id
分组,将剩余的值放回一起,并更新相应的行。
编辑 如果您的数据是对象中的嵌套数组,override the object on the specific key:
UPDATE bookmarks
SET tabsettings = filtered_elements.tabsettings
FROM (
SELECT id,
tabsettings || JSONB_BUILD_OBJECT('filters', JSONB_AGG(el)) as tabsettings
FROM bookmarks,
-- this must be an array
JSONB_ARRAY_ELEMENTS(tabsettings->'filters') AS el
WHERE el->>'field' != 'field_2'
GROUP BY id
) AS filtered_elements
WHERE filtered_elements.id = bookmarks.id;