更新 JSONField() 中的键值
Posted
技术标签:
【中文标题】更新 JSONField() 中的键值【英文标题】:Update key value in JSONField() 【发布时间】:2021-11-10 06:26:45 【问题描述】:我正在尝试批量更新大量记录(320 万条)。
这是我的模型:
class MyModel(models.Model):
stats = JSONField()
统计数据通常保存为:
"my_old_key": ["hey": "Hello World"]
我想更新它,以便只有键会改变它的值,最终统计信息看起来像这样(尽管已经有 "my_new_key"
的记录,所以最好以某种方式跳过这些记录):
"my_new_key": ["hey": "Hello World"]
我可以在 Python 中做到这一点,但它的工作速度真的很慢。我已经尝试使用来自 this link 的批处理方法处理约 10k 条记录,这样查询集就不会完全提取到内存中。最终解决方案如下所示:
def update_queryset(queryset) -> None:
for stat in queryset:
dictionary = stat.stats
if "my_old_key" in dictionary:
dictionary["my_new_key"] = dictionary.pop("my_old_key")
stat.save()
它确实有效,但不幸的是它运行得太慢了:(。
我曾想过根本不将它提取到 python 并纯粹在数据库 somewhat like this answer suggested 上工作,但没能成功。
关于如何加快速度/编写 RawSQL/使jsonb_set
方法起作用的任何建议?
编辑: 我事先过滤了查询集,以便跳过额外的 if 检查但无济于事。仍然工作缓慢..
queryset = MyModel.objects.filter(stats__has_key="my_old_key")
...
def update_queryset(queryset) -> None:
for stat in queryset:
dictionary = stat.stats
dictionary["my_new_key"] = dictionary.pop("my_old_key")
stat.save()
【问题讨论】:
你试过transaction.atomic()
吗?
使用docs.djangoproject.com/en/3.2/ref/models/querysets/#bulk-update
@codepylot 我刚刚做的,无论是用于包装整个 update_queryset
方法还是 save()
调用,似乎都没有使它更快:(。
@EneP 我知道 bulk_update 但我不太确定如何按照我描述的方式将它与 JSONField
一起使用。你能告诉我这是什么样子吗?
【参考方案1】:
def update_queryset(queryset) -> None:
for stat in queryset:
stat.stats["my_new_key"] = stat.stats.pop("my_old_key")
MyModel.objects.bulk_update(queryset, ['stats'])
【讨论】:
我不知道为什么,但是如果我使用批处理 link 或使用queryset.iterator()
我认为我应该处理 320 万条记录,此解决方案不会更新模型?编辑:它似乎没有批处理。以上是关于更新 JSONField() 中的键值的主要内容,如果未能解决你的问题,请参考以下文章
Spark入门--Spark的combineByKeysortBykey