【问题标题】:How to update JSONB array based on property name?如何根据属性名称更新 JSONB 数组?
【发布时间】:2019-05-06 16:44:56
【问题描述】:

我想根据 objectId 更新以下 JSON 数组的字段(存储在 JSONB 数据类型的列中)。

        [
            {
                objectId: 'gDKn1jM5d',
                objectType: 'type1',
                posX: 50,
                posY: 100,
            },
            {
                objectId: '4dg5E8BDv',
                objectType: 'type2',
                posX: 50,
                posY: 100,
            },
            {
                objectId: 'ZmCwOf5N2',
                objectType: 'type3',
                posX: 100,
                posY: 150,
            }
        ]

在 Mongodb 中,我可以使用简单的更新语句,但在 postgres 中找不到方法。

例如,我想将 objectId 'ZmCwOf5N2' 的所有数组元素更新为 posX 值 300(这意味着它只会影响第 3 个数组项)。

我正在寻找一个简单的 SQL 语句来执行更新。 postgres 版本是 11。

我无法安装扩展,因为我使用数据库作为服务提供者。但是,如果没有简单的方法来完成更新语句,我可以使用例如添加一个 postgres 函数。 C 代码。

【问题讨论】:

  • 明确的答案已发布@stackoverflow.com/questions/18209625/…
  • 我已经看到了,但它没有描述如何通过属性值更新数组项,而是仅通过数组索引。
  • 你可以查看我对这个问题的回答:stackoverflow.com/questions/55071171/…
  • 我也看到了。你知道这是否是唯一的解决方案吗?如果是这样,这意味着我猜还不支持条件(基于属性)数组操作。

标签: json postgresql


【解决方案1】:
UPDATE tbl t
SET    js = 
   (
   SELECT jsonb_agg(CASE WHEN elem->>'objectId' = 'ZmCwOf5N2'
                         THEN jsonb_set(elem, '{posX}', to_jsonb(int '300'))
                         ELSE elem
                    END) AS  js1 
   FROM   jsonb_array_elements(t.js) elem
   )
WHERE  t.js @> '[{"objectId": "ZmCwOf5N2"}]';

请注意,这个..

  • 如果缺少“posX”键,则添加它
  • 即使没有任何变化也会更新行

仅更新现有的键并且仅在更新实际更改值时更新行:

UPDATE tbl t
SET    js = 
   (
   SELECT jsonb_agg(CASE WHEN elem->>'objectId' = 'ZmCwOf5N2'
                         THEN jsonb_set(elem, '{posX}', to_jsonb(int '300'), false)  -- !
                         ELSE elem
                    END) AS  js1 
   FROM   jsonb_array_elements(t.js) elem
   )
WHERE  t.js @> '[{"objectId": "ZmCwOf5N2"}]'
AND    js <>
   (
   SELECT jsonb_agg(CASE WHEN elem->>'objectId' = 'ZmCwOf5N2'
                         THEN jsonb_set(elem, '{posX}', to_jsonb(int '300'), false)
                         ELSE elem
                    END) AS  js1 
   FROM   jsonb_array_elements(t.js) elem
   );  --!

见:

【讨论】:

  • 这看起来是一个很好的解决方案。非常感谢!您知道是否计划了原生解决方案(专门针对该用例的解决方案,因此可以用更少的代码完成)?
  • @microman:这是目前(Postgres 11)最短和最快的方法。 (还要注意我添加的变体!)为 Postgres 12 添加部分 SQL/JSON 路径语言。不确定是否会涵盖。
猜你喜欢
  • 1970-01-01
  • 2019-03-04
  • 2023-03-08
  • 2019-05-09
  • 2011-07-27
  • 2017-01-31
  • 1970-01-01
相关资源
最近更新 更多