使用 PostgreSQL 查询更新复杂 JSONB 对象以删除子子属性

Posted

技术标签:

【中文标题】使用 PostgreSQL 查询更新复杂 JSONB 对象以删除子子属性【英文标题】:Update a complex JSONB object to remove a sub-sub-property with a PostgreSQL query 【发布时间】:2021-02-03 07:01:18 【问题描述】:

假设我在 my_jsonb PostgreSQL 数据库表的列中有这样的 JSONB 数据,模式如下:

[
  
    "foo": 
      "bar": [
        
          "baz": 1,
          "qux": 2
        
      ]
    
  ,
  
    "foo": 
      "bar": [
        
          "baz": 3,
          "qux": 4
        ,
        
          "baz": 5,
          "qux": 6
        
      ]
    
  
]

换言之,my_jsonb 的每一列都有一个 foo 列表,该列表具有一个属性 bar,其中包含具有两个属性 bazqux 的对象数组。

我现在认为 baz 属性已过时,我想将其删除以拥有此:

[
  
    "foo": 
      "bar": [
        
          "qux": 2
        
      ]
    
  ,
  
    "foo": 
      "bar": [
        
          "qux": 4
        ,
        
          "qux": 6
        
      ]
    
  
]

我可以使用脚本在每个bar 项目中一个一个地删除这些baz 属性,但它会超长。有没有办法更新复杂的 JSONB 对象以删除子子属性而不用脚本做任何事情?

可以逐行进行(我的实际表中只有 100k 行,所以我认为迭代每一行是安全的,我唯一想要的就是 删除所有 baz属性在一行中一次)。

有可能吗?

【问题讨论】:

【参考方案1】:

如果 json 结构是刚性的,您可以通过以下方式重新创建 json 对象:

select id, jsonb_agg(new_foos order by fo)
from (
    select 
        id, fo, 
        jsonb_build_object(
            'foo', 
            jsonb_build_object(
                'bar', 
                jsonb_agg(bars- 'baz' order by bo))
        ) as new_foos
    from my_table
    cross join 
        jsonb_array_elements(json_data) 
        with ordinality as foos(foos, fo)
    cross join 
        jsonb_array_elements(foos->'foo'->'bar') 
        with ordinality as bars(bars, bo)
    group by id, fo
    ) s
group by id

请注意,我们使用具有 with ordinality 功能获得的顺序的聚合来保留数组元素的原始顺序。

Db<>Fiddle.

【讨论】:

还有一个问题:两个数组的顺序都保证了吗? 再次感谢您!也许您可以通过添加“替代”版本来更新您的帖子,并在原始版本之后保留顺序?它可以帮助其他读者找到合适的解决方案。如果你愿意,我也可以自己做。谢谢!

以上是关于使用 PostgreSQL 查询更新复杂 JSONB 对象以删除子子属性的主要内容,如果未能解决你的问题,请参考以下文章

jOOQ & PostgreSQL:将从复杂 jsonb 中提取的嵌套 json 对象映射到自定义类型

如何使用 JOOQ 在 PostgreSQL 中插入带有 JSON 列的可更新记录?

PostgreSQL Json字段作为查询条件案例

如何使用 laravel 更新 postgresql 数据库中的 json 数据?

如何使用新的 PostgreSQL JSON 数据类型中的字段进行查询?

PostgreSQL 查询包含特定键值的 json 对象中的行