Files
ent/doc/md/aggregate.md
Shivam Sandbhor 554b9d0850 doc/website: add docs for HAVING + GROUP BY clause (#2326)
* Add docs for HAVING + GROUP BY clause

Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>

* Make review changes for docs

Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
2022-02-15 10:21:16 +02:00

140 lines
2.4 KiB
Markdown
Executable File

---
id: aggregate
title: Aggregation
---
## Group By
Group by `name` and `age` fields of all users, and sum their total age.
```go
package main
import (
"context"
"<project>/ent"
"<project>/ent/user"
)
func Do(ctx context.Context, client *ent.Client) {
var v []struct {
Name string `json:"name"`
Age int `json:"age"`
Sum int `json:"sum"`
Count int `json:"count"`
}
err := client.User.Query().
GroupBy(user.FieldName, user.FieldAge).
Aggregate(ent.Count(), ent.Sum(user.FieldAge)).
Scan(ctx, &v)
}
```
Group by one field.
```go
package main
import (
"context"
"<project>/ent"
"<project>/ent/user"
)
func Do(ctx context.Context, client *ent.Client) {
names, err := client.User.
Query().
GroupBy(user.FieldName).
Strings(ctx)
}
```
## Group By Edge
Custom aggregation functions can be useful if you want to write your own storage-specific logic.
The following shows how to group by the `id` and the `name` of all users and calculate the average `age` of their pets.
```go
package main
import (
"context"
"log"
"<project>/ent"
"<project>/ent/pet"
"<project>/ent/user"
)
func Do(ctx context.Context, client *ent.Client) {
var users []struct {
ID int
Name string
Average float64
}
err := client.User.Query().
GroupBy(user.FieldID, user.FieldName).
Aggregate(func(s *sql.Selector) string {
t := sql.Table(pet.Table)
s.Join(t).On(s.C(user.FieldID), t.C(pet.OwnerColumn))
return sql.As(sql.Avg(t.C(pet.FieldAge)), "average")
}).
Scan(ctx, &users)
}
```
## Having + Group By
This example requires custom SQL modifiers. See how to enable them [here](https://entgo.io/docs/feature-flags/#custom-sql-modifiers)
In this example we're going to query the oldest users for each role.
```go
package main
import (
"context"
"log"
"entgo.io/ent/dialect/sql"
"<project>/ent"
"<project>/ent/user"
)
func Do(ctx context.Context, client *ent.Client) {
var users []struct {
Id Int
Age Int
Role string
}
client.User.Query().Modify(
func(s *sql.Selector) {
s.GroupBy(
User.Role,
)
s.Having(
sql.EQ(
user.FieldAge,
sql.Raw(sql.Max(user.FieldAge)),
),
)
}
).ScanX(ctx, &users)
}
```
**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:
```sql
SELECT * FROM user
GROUP BY user.role
HAVING user.age = MAX(user.age) ;
```