Postgresql 如何跨POSTGE中的所有表行从JSONB数组中删除节点?

Postgresql 如何跨POSTGE中的所有表行从JSONB数组中删除节点?,postgresql,jsonb,Postgresql,Jsonb,我有一个名为“Bookmarks”的表,其中包含几个标准行,还有一个名为“columnsettings”的JSONB列 此JSONB列的内容如下所示 [ { "data": "id", "width": 25 }, { "data": "field_1", "width": 125

我有一个名为“Bookmarks”的表,其中包含几个标准行,还有一个名为“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
    }
]
我正在尝试编写一条update语句,该语句将通过删除我指定的特定节点来更新此columnsettings。例如,我可能希望更新columnsettings,并仅删除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
但是,我希望它应用于表中的每一行。当有多行时,我得到错误“作为表达式使用的子查询返回多行”

如何让此查询更新表中的所有行


更新后,提供的答案解决了我的问题

现在我有了另一个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;
更新

如果数组中有多个“过滤器”,则此查询现在似乎可以工作。 但是,如果数组中只有一个元素应该被排除,它不会删除该项

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\u ARRAY\u元素
,可以将JSONB数组转换为行,每个对象一行,称之为
el
。然后,您可以访问
数据
属性以过滤掉“field_2”条目。最后,按
id
分组,将剩余的最小值放回一起,并更新相应的行


编辑如果数据是对象中的嵌套数组,则:


您可以解构、过滤和重新构造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\u ARRAY\u元素
,可以将JSONB数组转换为行,每个对象一行,称之为
el
。然后,您可以访问
数据
属性以过滤掉“field_2”条目。最后,按
id
分组,将剩余的最小值放回一起,并更新相应的行


编辑如果数据是对象中的嵌套数组,则:


嘿@Ruben,我用稍微不同的JSONB格式更新了我的问题。你能指出我在这个不同的JSONB格式上执行相同过滤的语法有什么错误吗?Thx,我尝试过这个方法,如果数组中有多个匹配的节点,它似乎可以工作。在这种情况下,它会正确地删除/筛选出节点。但是,如果数组中只有一个节点与我尝试筛选出的节点匹配,它将忽略该节点,并且该项将保留。有没有关于如何修复的想法?我会在一个单独的update语句中过滤掉这些情况<代码>其中JSONB_数组_长度(tabsettings->'filters')=1和tabsettings->'filters'->0->>'field'='field_2'并使用
-
操作符删除键。更多详细信息,请参见Hey@Ruben,我用稍微不同的JSONB格式更新了我的问题。你能指出我在这个不同的JSONB格式上执行相同过滤的语法有什么错误吗?Thx,我尝试过这个方法,如果数组中有多个匹配的节点,它似乎可以工作。在这种情况下,它会正确地删除/筛选出节点。但是,如果数组中只有一个节点与我尝试筛选出的节点匹配,它将忽略该节点,并且该项将保留。有没有关于如何修复的想法?我会在一个单独的update语句中过滤掉这些情况<代码>其中JSONB_数组_长度(tabsettings->'filters')=1和tabsettings->'filters'->0->>'field'='field_2'并使用
-
操作符删除键。有关更多详细信息,请参阅