mirror of
https://github.com/ent/ent.git
synced 2026-05-24 09:31:56 +03:00
269 lines
5.6 KiB
Plaintext
269 lines
5.6 KiB
Plaintext
---
|
|
id: paging
|
|
title: Paging And Ordering
|
|
---
|
|
|
|
import Tabs from '@theme/Tabs';
|
|
import TabItem from '@theme/TabItem';
|
|
|
|
## Limit
|
|
|
|
`Limit` limits the query result to `n` entities.
|
|
|
|
```go
|
|
users, err := client.User.
|
|
Query().
|
|
Limit(n).
|
|
All(ctx)
|
|
```
|
|
|
|
|
|
## Offset
|
|
|
|
`Offset` sets the first node to return from the query.
|
|
|
|
```go
|
|
users, err := client.User.
|
|
Query().
|
|
Offset(10).
|
|
All(ctx)
|
|
```
|
|
|
|
## Ordering
|
|
|
|
`Order` returns the entities sorted by the values of one or more fields. Note that, an error
|
|
is returned if the given fields are not valid columns or foreign-keys.
|
|
|
|
```go
|
|
users, err := client.User.Query().
|
|
Order(ent.Asc(user.FieldName)).
|
|
All(ctx)
|
|
```
|
|
|
|
Starting with version `v0.12.0`, Ent generates type-safe ordering functions for fields and edges. The following
|
|
example demonstrates how to use these generated functions:
|
|
|
|
```go
|
|
// Get all users sorted by their name (and nickname) in ascending order.
|
|
users, err := client.User.Query().
|
|
Order(
|
|
// highlight-start
|
|
user.ByName(),
|
|
user.ByNickname(),
|
|
// highlight-end
|
|
).
|
|
All(ctx)
|
|
|
|
// Get all users sorted by their nickname in descending order.
|
|
users, err := client.User.Query().
|
|
Order(
|
|
// highlight-start
|
|
user.ByNickname(
|
|
sql.OrderDesc(),
|
|
),
|
|
// highlight-end
|
|
).
|
|
All(ctx)
|
|
```
|
|
|
|
## Order By Edge Count
|
|
|
|
`Order` can also be used to sort entities based on the number of edges they have. For example, the following query
|
|
returns all users sorted by the number of posts they have:
|
|
|
|
```go
|
|
users, err := client.User.Query().
|
|
Order(
|
|
// highlight-start
|
|
// Users without posts are sorted first.
|
|
user.ByPostsCount(),
|
|
// highlight-end
|
|
).
|
|
All(ctx)
|
|
|
|
users, err := client.User.Query().
|
|
Order(
|
|
// highlight-start
|
|
// Users without posts are sorted last.
|
|
user.ByPostsCount(
|
|
sql.OrderDesc(),
|
|
),
|
|
// highlight-end
|
|
).
|
|
All(ctx)
|
|
```
|
|
|
|
## Order By Edge Field
|
|
|
|
Entities can also be sorted by the value of an edge field. For example, the following query returns all posts sorted by
|
|
their author's name:
|
|
|
|
```go
|
|
// Posts are sorted by their author's name in ascending
|
|
// order with NULLs first unless otherwise specified.
|
|
posts, err := client.Post.Query().
|
|
Order(
|
|
// highlight-next-line
|
|
post.ByAuthorField(user.FieldName),
|
|
).
|
|
All(ctx)
|
|
|
|
posts, err := client.Post.Query().
|
|
Order(
|
|
// highlight-start
|
|
post.ByAuthorField(
|
|
user.FieldName,
|
|
sql.OrderDesc(),
|
|
sql.OrderNullsFirst(),
|
|
),
|
|
// highlight-end
|
|
).
|
|
All(ctx)
|
|
```
|
|
|
|
## Custom Edge Terms
|
|
|
|
The generated edge ordering functions support custom terms. For example, the following query returns all users sorted
|
|
by the sum of their posts' likes and views:
|
|
|
|
```go
|
|
// Ascending order.
|
|
posts, err := client.User.Query().
|
|
Order(
|
|
// highlight-start
|
|
user.ByPosts(
|
|
sql.OrderBySum(post.FieldNumLikes),
|
|
sql.OrderBySum(post.FieldNumViews),
|
|
),
|
|
// highlight-end
|
|
).
|
|
All(ctx)
|
|
|
|
// Descending order.
|
|
posts, err := client.User.Query().
|
|
Order(
|
|
// highlight-start
|
|
user.ByPosts(
|
|
sql.OrderBySum(
|
|
post.FieldNumLikes,
|
|
sql.OrderDesc(),
|
|
),
|
|
sql.OrderBySum(
|
|
post.FieldNumViews,
|
|
sql.OrderDesc(),
|
|
),
|
|
),
|
|
// highlight-end
|
|
).
|
|
All(ctx)
|
|
```
|
|
|
|
## Select Order Terms
|
|
|
|
Ordered terms like `SUM()` and `COUNT()` are not defined in the schema and thus do not exist on the generated entities.
|
|
However, sometimes there is a need to retrieve their information in order to either display it to the user or implement
|
|
cursor-based pagination. The `Value` method, defined on each entity, allows you to obtain the order value if it was
|
|
selected in the query:
|
|
|
|
```go
|
|
// Define the alias for the order term.
|
|
const as = "pets_count"
|
|
|
|
// Query users sorted by the number of pets
|
|
// they have and select the order term.
|
|
users := client.User.Query().
|
|
Order(
|
|
user.ByPetsCount(
|
|
sql.OrderDesc(),
|
|
// highlight-next-line
|
|
sql.OrderSelectAs(as),
|
|
),
|
|
user.ByID(),
|
|
).
|
|
AllX(ctx)
|
|
|
|
// Retrieve the order term value.
|
|
for _, u := range users {
|
|
// highlight-next-line
|
|
fmt.Println(u.Value(as))
|
|
}
|
|
```
|
|
|
|
## Custom Ordering
|
|
|
|
Custom ordering functions can be useful if you want to write your own storage-specific logic.
|
|
|
|
```go
|
|
names, err := client.Pet.Query().
|
|
Order(func(s *sql.Selector) {
|
|
// Logic goes here.
|
|
}).
|
|
Select(pet.FieldName).
|
|
Strings(ctx)
|
|
```
|
|
|
|
#### Order by JSON fields
|
|
|
|
The [`sqljson`](https://pkg.go.dev/entgo.io/ent/dialect/sql/sqljson) package allows to easily sort data based on the
|
|
value of a JSON object:
|
|
|
|
<Tabs>
|
|
<TabItem value="value" label="By Value" default>
|
|
|
|
```go {3}
|
|
users := client.User.Query().
|
|
Order(
|
|
sqljson.OrderValue(user.FieldData, sqljson.Path("key1", "key2")),
|
|
).
|
|
AllX(ctx)
|
|
```
|
|
|
|
</TabItem>
|
|
<TabItem value="length" label="By Length">
|
|
|
|
```go {3}
|
|
users := client.User.Query().
|
|
Order(
|
|
sqljson.OrderLen(user.FieldData, sqljson.Path("key1", "key2")),
|
|
).
|
|
AllX(ctx)
|
|
```
|
|
|
|
</TabItem>
|
|
<TabItem value="desc" label="Descending">
|
|
|
|
```go {3,9}
|
|
users := client.User.Query().
|
|
Order(
|
|
sqljson.OrderValueDesc(user.FieldData, sqljson.Path("key1", "key2")),
|
|
).
|
|
AllX(ctx)
|
|
|
|
pets := client.Pet.Query().
|
|
Order(
|
|
sqljson.OrderLenDesc(pet.FieldData, sqljson.Path("key1", "key2")),
|
|
).
|
|
AllX(ctx)
|
|
```
|
|
|
|
</TabItem>
|
|
</Tabs>
|
|
|
|
<details>
|
|
<summary>PostgreSQL limitation on <code>ORDER BY</code> expressions with <code>SELECT DISTINCT</code></summary>
|
|
<div>
|
|
|
|
PostgreSQL does not support `ORDER BY` expressions with `SELECT DISTINCT`. Thus, the `Unique` modifier should be set
|
|
to `false`. However, keep in mind that this may result in duplicate results when performing graph traversals.
|
|
|
|
```diff
|
|
users := client.User.Query().
|
|
Order(
|
|
sqljson.OrderValue(user.FieldData, sqljson.Path("key1", "key2")),
|
|
).
|
|
+ Unique(false).
|
|
AllX(ctx)
|
|
```
|
|
|
|
</div>
|
|
</details> |