简体   繁体   English

如何删除/更新键等于值的 JSONB 数组元素?

[英]How to remove/update a JSONB array element where key equals a value?

I'd like remove/replace an element from a JSONB array where a property is equal to a set value.我想从属性等于设定值的 JSONB 数组中删除/替换一个元素。 I've found a number of functions that will accomplish this but I'd like to know if there's a way to do it without one as I have database restrictions?我已经找到了许多可以完成此操作的功能,但我想知道是否有一种方法可以做到这一点,因为我有数据库限制?

Here's an example JSONB value:这是一个示例 JSONB 值:

[
  { "ID": "valuea" },
  { "ID": "valueb" },
  { "ID": "valuec" }
]

I'd like to remove the second array position where ID is equal to valueb with a single update statement.我想用一条更新语句删除第二个数组 position,其中 ID 等于valueb I'd imagine this could finding the position/order in the array, jsonb_set() to remove it.我想这可以找到数组中的位置/顺序, jsonb_set()将其删除。

It would also be helpful if there was a way to update the row and not just remove it.如果有一种方法可以更新行而不仅仅是删除它,那也会很有帮助。 Likely a similar query, again with jsonb_set() .可能是类似的查询,再次使用jsonb_set()

Unfortunately, there is no function to return the position of a JSON array element (yet) as of Postgres 15.不幸的是,从 Postgres 15 开始,没有 function 返回 JSON 数组元素的 position(目前)。

To remove a single matching element:要删除单个匹配元素:

UPDATE tbl t
SET    js = t.js - (SELECT j.ord::int - 1
                    FROM   jsonb_array_elements(t.js) WITH ORDINALITY j(v,ord)
                    WHERE  j.v = '{"ID": "valueb"}'
                    LIMIT  1)
WHERE  t.js @> '[{"ID": "valueb"}]'   -- optional
AND    jsonb_typeof(t.js) = 'array';  -- optional

This UPDATE uses a correlated subquery with jsonb_array_elements() .UPDATE使用与jsonb_array_elements()相关的子查询。
About WITH ORDINALITY :关于WITH ORDINALITY

Both WHERE clauses are optional.两个WHERE子句都是可选的。

  • Use the filter t.js @> '[{"ID": "valueb"}]' to suppress (potentially expensive!) empty updates and make good use of an existing GIN index on the jsonb column使用过滤器t.js @> '[{"ID": "valueb"}]'来抑制(可能很昂贵!)空更新并充分利用jsonb列上的现有 GIN 索引

  • Use the filter jsonb_typeof(t.js) = 'array' to only suppress errors from non-arrays.使用过滤器jsonb_typeof(t.js) = 'array'只抑制来自非数组的错误。

Note how the outer filter includes enclosing array decorators [] , while the inner filter (after unnesting) does not.请注意外部过滤器如何包含封闭的数组装饰器[] ,而内部过滤器(在取消嵌套之后)不包含。

To remove all matching elements:要删除所有匹配元素:

UPDATE tbl t
SET    js = (SELECT jsonb_agg(j.v)
             FROM   jsonb_array_elements(t.js) j(v)
             WHERE  NOT j.v @> '{"ID": "valueb"}')
WHERE  t.js @> '[{"ID": "valueb"}]';

fiddle小提琴

The second query aggregates a new array from remaining elements.第二个查询从剩余元素聚合一个新数组。

This time, the inner filter uses @> instead of = to allow for additional keys.这一次,内部过滤器使用@>而不是=来允许额外的键。 Chose the appropriate filter.选择合适的过滤器。

Aside: jsonb_set() might be useful additionally if the array in question is actually nested, unlike your example.旁白:如果所讨论的数组实际上是嵌套的,则jsonb_set()可能还有用,这与您的示例不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM