Indexes
Note that for setting a single field as unique, use the method on the field builder as follows:
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.
// 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
example.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").
client.Street.
Create().
SetName("ST").
SetCity(tlv).
SaveX(ctx)
// This operation fails because "ST"
// was already created under "TLV".
if err := client.Street.
Create().
SetName("ST").
SetCity(tlv).
Exec(ctx); 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 .
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.
// 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 {
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
The code above generates the following SQL statements:
CREATE INDEX `users_description` ON `users`(`description`(128))
CREATE INDEX `users_c1_c2_c3` ON `users`(`c1`(100), `c2`(200), `c3`)
Starting with v0.10, Ent supports running migration with Atlas. This option provides more control on indexes such as, configuring their types or define indexes in a reverse order.
func (User) Indexes() []ent.Index {
return []ent.Index{
index.Fields("c1").
Annotations(entsql.Desc()),
index.Fields("c1", "c2", "c3").
Annotation(entsql.DescColumns("c1", "c2")),
index.Fields("c4").
Annotations(entsql.IndexType("HASH")),
// Enable FULLTEXT search on MySQL,
// and GIN on PostgreSQL.
index.Fields("c5").
Annotations(
entsql.IndexTypes(map[string]string{
dialect.MySQL: "FULLTEXT",
dialect.Postgres: "GIN",
}),
),
}
}
The code above generates the following SQL statements:
Storage Key
Like Fields, custom index name can be configured using the StorageKey
method. It’s mapped to a index name in SQL dialects.
func (User) Indexes() []ent.Index {
return []ent.Index{
index.Fields("field1", "field2").
StorageKey("custom_index"),
}