Files
ent/doc/md/eager-load.mdx
Ariel Mashraki b60e0f9eac entc/gen: add support for WithNamed<E> feature-flag (#2792)
* entc/gen: struct fields and methods for NamedEdge api

* entc/gen: generate WithNamedEdge methods for named-edges

* entc/gen: implement eager-loading for named-edges

* entc/gen: simplify eager-loading template

* entc/gen: drop support for unqiue edges in named-based loading

* all: codegen

* doc/website: named-edges feature-flag

* Update doc/md/eager-load.mdx

* Update doc/md/eager-load.mdx
2022-07-24 18:41:07 +03:00

193 lines
4.3 KiB
Plaintext

---
id: eager-load
title: Eager Loading
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Overview
`ent` supports querying entities with their associations (through their edges). The associated entities
are populated to the `Edges` field in the returned object.
Let's give an example of what the API looks like for the following schema:
![er-group-users](https://entgo.io/images/assets/er_user_pets_groups.png)
**Query all users with their pets:**
```go
users, err := client.User.
Query().
WithPets().
All(ctx)
if err != nil {
return err
}
// The returned users look as follows:
//
// [
// User {
// ID: 1,
// Name: "a8m",
// Edges: {
// Pets: [Pet(...), ...]
// ...
// }
// },
// ...
// ]
//
for _, u := range users {
for _, p := range u.Edges.Pets {
fmt.Printf("User(%v) -> Pet(%v)\n", u.ID, p.ID)
// Output:
// User(...) -> Pet(...)
}
}
```
Eager loading allows to query more than one association (including nested), and also
filter, sort or limit their result. For example:
```go
admins, err := client.User.
Query().
Where(user.Admin(true)).
// Populate the `pets` that associated with the `admins`.
WithPets().
// Populate the first 5 `groups` that associated with the `admins`.
WithGroups(func(q *ent.GroupQuery) {
q.Limit(5) // Limit to 5.
q.WithUsers() // Populate the `users` of each `groups`.
}).
All(ctx)
if err != nil {
return err
}
// The returned users look as follows:
//
// [
// User {
// ID: 1,
// Name: "admin1",
// Edges: {
// Pets: [Pet(...), ...]
// Groups: [
// Group {
// ID: 7,
// Name: "GitHub",
// Edges: {
// Users: [User(...), ...]
// ...
// }
// }
// ]
// }
// },
// ...
// ]
//
for _, admin := range admins {
for _, p := range admin.Edges.Pets {
fmt.Printf("Admin(%v) -> Pet(%v)\n", u.ID, p.ID)
// Output:
// Admin(...) -> Pet(...)
}
for _, g := range admin.Edges.Groups {
for _, u := range g.Edges.Users {
fmt.Printf("Admin(%v) -> Group(%v) -> User(%v)\n", u.ID, g.ID, u.ID)
// Output:
// Admin(...) -> Group(...) -> User(...)
}
}
}
```
## API
Each query-builder has a list of methods in the form of `With<E>(...func(<N>Query))` for each of its edges.
`<E>` stands for the edge name (like, `WithGroups`) and `<N>` for the edge type (like, `GroupQuery`).
Note that only SQL dialects support this feature.
## Named Edges
In some cases there is a need for preloading edges with custom names. For example, a GraphQL query that has two aliases
referencing the same edge with different arguments. For this situation, Ent provides another API named `WithNamed<E>`
that can be enabled using the [`namedges`](features.md#named-edges) feature-flag and seamlessly integrated with
[EntGQL Fields Collection](tutorial-todo-gql-field-collection.md).
<Tabs
defaultValue="ent"
values={[
{label: 'Ent', value: 'ent'},
{label: 'GraphQL', value: 'graphql'},
]}>
<TabItem value="ent">
See the GraphQL tab to learn more about the motivation behind this API.
```go
posts, err := client.Post.Query().
WithNamedComments("published", func(q *ent.CommentQuery) {
q.Where(comment.StatusEQ(comment.StatusPublished))
})
WithNamedComments("draft", func(q *ent.CommentQuery) {
q.Where(comment.StatusEQ(comment.StatusDraft))
}).
Paginate(...)
// Get the preloaded edges by their name:
for _, p := range posts {
published, err := p.Edges.NamedComments("published")
if err != nil {
return err
}
draft, err := p.Edges.NamedComments("draft")
if err != nil {
return err
}
}
```
</TabItem>
<TabItem value="graphql">
An example of a GraphQL query that has two aliases referencing the same edge with different arguments.
```graphql
query {
posts {
id
title
published: comments(where: { status: PUBLISHED }) {
edges {
node {
text
}
}
}
draft: comments(where: { status: DRAFT }) {
edges {
node {
text
}
}
}
}
}
```
</TabItem>
</Tabs>
## Implementation
Since an Ent query can eager-load more than one edge, it is not possible to load all associations in a single
`JOIN` operation. Therefore, Ent executes additional query to load each association. This expected to be optimized
in future versions.