mirror of
https://github.com/ent/ent.git
synced 2026-04-29 22:20:54 +03:00
216 lines
4.5 KiB
Markdown
Executable File
216 lines
4.5 KiB
Markdown
Executable File
---
|
|
id: schema-indexes
|
|
title: Indexes
|
|
---
|
|
|
|
## Multiple Fields
|
|
|
|
Indexes can be configured on one or more fields in order to improve
|
|
speed of data retrieval, or defining uniqueness.
|
|
|
|
```go
|
|
package schema
|
|
|
|
import (
|
|
"entgo.io/ent"
|
|
"entgo.io/ent/schema/index"
|
|
)
|
|
|
|
// User holds the schema definition for the User entity.
|
|
type User struct {
|
|
ent.Schema
|
|
}
|
|
|
|
func (User) Indexes() []ent.Index {
|
|
return []ent.Index{
|
|
// non-unique index.
|
|
index.Fields("field1", "field2"),
|
|
// unique index.
|
|
index.Fields("first_name", "last_name").
|
|
Unique(),
|
|
}
|
|
}
|
|
```
|
|
|
|
Note that for setting a single field as unique, use the `Unique`
|
|
method on the field builder as follows:
|
|
|
|
```go
|
|
func (User) Fields() []ent.Field {
|
|
return []ent.Field{
|
|
field.String("phone").
|
|
Unique(),
|
|
}
|
|
}
|
|
```
|
|
|
|
## Index On Edges
|
|
|
|
Indexes can be configured on composition of fields and edges. The main use-case
|
|
is setting uniqueness on fields under a specific relation. Let's take an example:
|
|
|
|

|
|
|
|
In the example above, we have a `City` with many `Street`s, and we want to set the
|
|
street name to be unique under each city.
|
|
|
|
`ent/schema/city.go`
|
|
```go
|
|
// City holds the schema definition for the City entity.
|
|
type City struct {
|
|
ent.Schema
|
|
}
|
|
|
|
// Fields of the City.
|
|
func (City) Fields() []ent.Field {
|
|
return []ent.Field{
|
|
field.String("name"),
|
|
}
|
|
}
|
|
|
|
// Edges of the City.
|
|
func (City) Edges() []ent.Edge {
|
|
return []ent.Edge{
|
|
edge.To("streets", Street.Type),
|
|
}
|
|
}
|
|
```
|
|
|
|
`ent/schema/street.go`
|
|
```go
|
|
// Street holds the schema definition for the Street entity.
|
|
type Street struct {
|
|
ent.Schema
|
|
}
|
|
|
|
// Fields of the Street.
|
|
func (Street) Fields() []ent.Field {
|
|
return []ent.Field{
|
|
field.String("name"),
|
|
}
|
|
}
|
|
|
|
// Edges of the Street.
|
|
func (Street) Edges() []ent.Edge {
|
|
return []ent.Edge{
|
|
edge.From("city", City.Type).
|
|
Ref("streets").
|
|
Unique(),
|
|
}
|
|
}
|
|
|
|
// Indexes of the Street.
|
|
func (Street) Indexes() []ent.Index {
|
|
return []ent.Index{
|
|
index.Fields("name").
|
|
Edges("city").
|
|
Unique(),
|
|
}
|
|
}
|
|
```
|
|
|
|
`example.go`
|
|
```go
|
|
func Do(ctx context.Context, client *ent.Client) error {
|
|
// Unlike `Save`, `SaveX` panics if an error occurs.
|
|
tlv := client.City.
|
|
Create().
|
|
SetName("TLV").
|
|
SaveX(ctx)
|
|
nyc := client.City.
|
|
Create().
|
|
SetName("NYC").
|
|
SaveX(ctx)
|
|
// Add a street "ST" to "TLV".
|
|
client.Street.
|
|
Create().
|
|
SetName("ST").
|
|
SetCity(tlv).
|
|
SaveX(ctx)
|
|
// This operation will fail because "ST"
|
|
// is already created under "TLV".
|
|
_, err := client.Street.
|
|
Create().
|
|
SetName("ST").
|
|
SetCity(tlv).
|
|
Save(ctx)
|
|
if err == nil {
|
|
return fmt.Errorf("expecting creation to fail")
|
|
}
|
|
// Add a street "ST" to "NYC".
|
|
client.Street.
|
|
Create().
|
|
SetName("ST").
|
|
SetCity(nyc).
|
|
SaveX(ctx)
|
|
return nil
|
|
}
|
|
```
|
|
|
|
The full example exists in [GitHub](https://github.com/ent/ent/tree/master/examples/edgeindex).
|
|
|
|
## Index On Edge Fields
|
|
|
|
Currently `Edges` columns are always added after `Fields` columns. However, some indexes require these columns to come first in order to achieve specific optimizations. You can work around this problem by making use of [Edge Fields](schema-edges.md#edge-field).
|
|
|
|
```go
|
|
// Card holds the schema definition for the Card entity.
|
|
type Card struct {
|
|
ent.Schema
|
|
}
|
|
// Fields of the Card.
|
|
func (Card) Fields() []ent.Field {
|
|
return []ent.Field{
|
|
field.String("number").
|
|
Optional(),
|
|
field.Int("owner_id").
|
|
Optional(),
|
|
}
|
|
}
|
|
// Edges of the Card.
|
|
func (Card) Edges() []ent.Edge {
|
|
return []ent.Edge{
|
|
edge.From("owner", User.Type).
|
|
Ref("card").
|
|
Field("owner_id").
|
|
Unique(),
|
|
}
|
|
}
|
|
// Indexes of the Card.
|
|
func (Card) Indexes() []ent.Index {
|
|
return []ent.Index{
|
|
index.Fields("owner_id", "number"),
|
|
}
|
|
}
|
|
```
|
|
|
|
## Dialect Support
|
|
|
|
Indexes currently support only SQL dialects, and do not support Gremlin. Dialect specific features are allowed using
|
|
[annotations](schema-annotations.md). For example, in order to use [index prefixes](https://dev.mysql.com/doc/refman/8.0/en/column-indexes.html#column-indexes-prefix)
|
|
in MySQL, use the following configuration:
|
|
|
|
```go
|
|
// Indexes of the User.
|
|
func (User) Indexes() []ent.Index {
|
|
return []ent.Index{
|
|
index.Fields("description").
|
|
Annotations(entsql.Prefix(128)),
|
|
index.Fields("c1", "c2", "c3").
|
|
Annotation(
|
|
entsql.PrefixColumn("c1", 100),
|
|
entsql.PrefixColumn("c2", 200),
|
|
)
|
|
}
|
|
}
|
|
```
|
|
|
|
The code above generates the following SQL statements:
|
|
|
|
```sql
|
|
CREATE INDEX `users_description` ON `users`(`description`(128))
|
|
|
|
CREATE INDEX `users_c1_c2_c3` ON `users`(`c1`(100), `c2`(200), `c3`)
|
|
```
|
|
|