postgresql Django使用Postgres在JSONField中注解计数

enxuqcxy  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(1)|浏览(132)

使用Django我有一个类型为JSONField的字段。我想在JSON中的嵌套键/值上获得一个独特的计数。对于普通字段,您可以执行以下操作

model.objects.values('field_name')\
.annotate(total=Count('field_name')).order_by('-total')

这不适用于JSONField。
示例模型

class Pet(models.Model):
    data = JSONField()

数据示例

{
    'name':'sparky',
    'animal':'dog',
    'diet':{
        'breakfast':'biscuits',
        'dinner':'meat',
    }
}

努力

Pet.objects.values('data__diet__dinner')\
.annotate(total=Count('data__diet__dinner')).order_by('-total')

例外

TypeError: unhashable type: 'list'

正确的执行方式是什么?

yacmzcpb

yacmzcpb1#

您可以通过Func对象使用jsonb_extract_path_text作为字段转换的替代方法:

from django.db.models.aggregates import Count
from django.db.models.expressions import F, Func, Value

pets = (
    Pet.objects.annotate(
        dinner=Func(
            F("data"),
            Value("diet"),
            Value("dinner"),
            function="jsonb_extract_path_text",
        )
    )
    .values("dinner")
    .annotate(total=Count("dinner"))
)

字段转换data__diet__dinner失败的原因是Django中的一个错误,当你深入到json结构 * 和 * 在SQL中使用GROUP BY时。第一级(nameanimaldiet)应该可以正常工作。
原因似乎是,对于嵌套转换,Django更改了使用的SQL语法,从单个值切换到列表以指定json结构的路径。
这是用于非嵌套json转换的语法(=第一级):

"appname_pet"."data" -> 'diet'

这是用于嵌套转换的语法(比第一级更深):

"appname_pet"."data" #> ARRAY['diet', 'dinner']

在构造查询时,Django在计算所需的GROUP BY子句时阻塞了该列表。这似乎不是一个必然的限制;对转换的支持是相当新的,这可能是尚未解决的问题之一。因此,如果你打开一个Django ticket,这可能只是几个版本的工作。

相关问题