使用 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
,其中包含具有两个属性 baz
和 qux
的对象数组。
我现在认为 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 列的可更新记录?
如何使用 laravel 更新 postgresql 数据库中的 json 数据?