更新 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() 中的键值的主要内容,如果未能解决你的问题,请参考以下文章

如何获取自己键盘上按键的键值(KeyCode)

Spark入门--Spark的combineByKeysortBykey

安全地更新NSManagedObjects的键值

在Cassandra中用新的键值对更新地图类型列,而不是完全覆盖地图。

无法更新 NSUserDefaults 中字典的键值

C 语言文件操作 ( 配置文件读写 | 写出或更新配置文件 | 追加键值对数据 | 更新键值对数据 )