聚合

分组

对 users 按 nameage 字段分组,并计算 age 的总和。

  1. package main
  2. import (
  3. "context"
  4. "<project>/ent"
  5. "<project>/ent/user"
  6. )
  7. func Do(ctx context.Context, client *ent.Client) {
  8. var v []struct {
  9. Name string `json:"name"`
  10. Age int `json:"age"`
  11. Sum int `json:"sum"`
  12. Count int `json:"count"`
  13. }
  14. err := client.User.Query().
  15. GroupBy(user.FieldName, user.FieldAge).
  16. Aggregate(ent.Count(), ent.Sum(user.FieldAge)).
  17. Scan(ctx, &v)
  18. }

按单个字段分组.

  1. package main
  2. import (
  3. "context"
  4. "<project>/ent"
  5. "<project>/ent/user"
  6. )
  7. func Do(ctx context.Context, client *ent.Client) {
  8. names, err := client.User.
  9. Query().
  10. GroupBy(user.FieldName).
  11. Strings(ctx)
  12. }

根据边进行分组

如果您想按照自己的逻辑进行聚合,可以使用自定义聚合函数。

下面展示了:如何根据用户的 idname 进行分组,并计算其宠物的平均 age

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "<project>/ent"
  6. "<project>/ent/pet"
  7. "<project>/ent/user"
  8. )
  9. func Do(ctx context.Context, client *ent.Client) {
  10. var users []struct {
  11. ID int
  12. Name string
  13. Average float64
  14. }
  15. err := client.User.Query().
  16. GroupBy(user.FieldID, user.FieldName).
  17. Aggregate(func(s *sql.Selector) string {
  18. t := sql.Table(pet.Table)
  19. s.Join(t).On(s.C(user.FieldID), t.C(pet.OwnerColumn))
  20. return sql.As(sql.Avg(t.C(pet.FieldAge)), "average")
  21. }).
  22. Scan(ctx, &users)
  23. }

Having + Group By

Custom SQL modifiers can be useful if you want to control all query parts. The following shows how to retrieve the oldest users for each role.

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "entgo.io/ent/dialect/sql"
  6. "<project>/ent"
  7. "<project>/ent/user"
  8. )
  9. func Do(ctx context.Context, client *ent.Client) {
  10. var users []struct {
  11. Id Int
  12. Age Int
  13. Role string
  14. }
  15. err := client.User.Query().
  16. Modify(func(s *sql.Selector) {
  17. s.GroupBy(user.Role)
  18. s.Having(
  19. sql.EQ(
  20. user.FieldAge,
  21. sql.Raw(sql.Max(user.FieldAge)),
  22. ),
  23. )
  24. }).
  25. ScanX(ctx, &users)
  26. }

Note: The sql.Raw is crucial to have. It tells the predicate that sql.Max is not an arguement.

The above code essentially generates the following SQL query:

  1. SELECT * FROM user GROUP BY user.role HAVING user.age = MAX(user.age)