【问题标题】:django - aggregate json field specific keys and order by the aggregationdjango - 聚合 json 字段特定键并按聚合排序
【发布时间】:2017-12-31 07:14:45
【问题描述】:


我有一个模型,其字段为data,类型为JSONField,来自django.contrib.postgres.fields。 json结构是这样的:

{'aa': 1, 'bb': 2, 'cc': 4}

我想汇总 aacc 键的总和 - 所以在这种情况下,它将是 5。另外 - 我不能保证 aacc 将在 json 中。
这可能吗?如果是这样 - 我想按汇总数据排序。
示例:

  1. id: 1, data = {'aa': 1, 'bb': 2, 'cc':4}
  2. id: 2, data = {'aa': 3, 'bb': 2}
  3. id: 3, 数据 = {'cc': 7}
  4. id: 4, 数据 = {'bb': 7}

我想做一个查询,例如:
MyModel.objects.aggregate(my_sum).order_by(my_sum)
聚合后查询集中的有序行将是:

  1. id:3
  2. id:1
  3. id:2
  4. id:4

谢谢!

【问题讨论】:

  • 您拥有哪种类型的模型对象(实例或查询集)?
  • @NeErAjKuMaR - 我有一个查询集,我想根据模型字段聚合并按聚合值排序
  • 但你说你需要来自 json 数据的键值总和
  • @NeErAjKuMaR - 我添加了一个示例来尝试阐明我的需求。如果这回答了您的问题,请告诉我。
  • 您根据 aa 和 cc 键的总和对查询集进行排序,对吗?

标签: python django postgresql django-queryset django-jsonfield


【解决方案1】:

我知道您想对每一行的 a 值和 b 值求和,然后按总和值对每一行进行排序。对吧?

-> ->>这是在PostgreSQL中如何选择JSON格式的键或值(我不知道它是否也适用于MySQL或其他,我通常使用PostgreSQL)。 here 有很好的资源。您在名为“data”的列中的数据是{"aa":3, "bb":2, "cc":5}。所以你通过data->>'aa' 选择一个值。如果{'classification':{'pc':5000}} 怎么办?您需要选择 pc 值。然后data->'classification'->>'pc'

:: 表示法是强制转换操作。

CAST(data->'aa' AS INTEGER)

data->'aa'::int

类 RawSQL(sql, params, output_field=None)

RawSQL("((data->>'aa'::int), (0,)") 并不意味着如果aa不存在,它的值为0。0是params。

queryset.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))

好吧,如果你能像这样修改你的数据

  • id: 1, data = {'aa': 1, 'bb': 2, 'cc':4}
  • id: 2, data = {'aa': 3, 'bb': 2, 'cc':0}
  • id: 3, data = {'cc': 7, 'bb': 0, 'cc':0}
  • id: 4, data = {'bb': 7, 'bb': 0, 'cc':0}

这可以工作。

Contract.objects.annotate(
sumVal=RawSQL("((data->>'aa')::int)", (0,))+RawSQL("((data->>'cc')::int)",(0,)))
.order_by('sumVal')

我建议使用 Coalesce。这个问题的作者想通了。下面有代码。

raw_sql = "+".join(["COALESCE((data->>%s)::int, 0)" for _ in ['aa', 'cc']) 
MyMoodel.objects.all()
.annotate(my_sum=RawSQL(raw_sql, params=('aa', 'cc')))
.order_by('my_sum')

【讨论】:

  • 我试图用 Coalesce 来解决当键 'aa' 或 'cc' 不存在时的情况。这是一个有趣的问题,所以我花了很多时间来弄清楚,但我做不到。你可以查看django manual about Coalesce。我希望它能给您解决问题的任何想法。
  • 所以我想出了如何使用 Coalesce。这是我使用的语句:raw_sql = "+".join(["COALESCE((data->>%s)::int, 0)" for _ in ['aa', 'cc']) 然后运行MyMoodel.objects.all().annotate(my_sum=RawSQL(raw_sql, params=('aa', 'cc'))).order_by('my_sum') 请更新您的答案,我很乐意将其标记为答案
  • 哦,成功了吗?凉爽的。我尝试将 COALESCE 放入注释中,但没有成功。
【解决方案2】:
 YourModel.objects.annotate(aa=RawSQL("((data->>'aa')::int)", (0,)),
                            cc=RawSQL("((data->>'cc')::int)", (0,))) \
                .aggregate(total=Sum('aa')+Sum('cc')).order_by('total')

【讨论】:

    猜你喜欢
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2021-01-30
    • 2018-11-15
    • 1970-01-01
    • 2017-11-04
    • 2016-06-04
    • 1970-01-01
    相关资源
    最近更新 更多