Many To Many

Many to Many add a join table between two models.

For example, if your application includes users and languages, and a user can speak many languages, and many users can speak a specified language.

1. // User has and belongs to many languages, `user_languages` is the join table
2. type User struct {
3. gorm.Model
4. Languages []Language `gorm:"many2many:user_languages;"`
5. }

7. type Language struct {
8. gorm.Model
9. Name string
10. }

When using GORM AutoMigrate to create a table for User, GORM will create the join table automatically

Back-Reference

1. // User has and belongs to many languages, use `user_languages` as join table
2. type User struct {
3. gorm.Model
4. Languages []*Language `gorm:"many2many:user_languages;"`
5. }

7. type Language struct {
8. gorm.Model
9. Name string
10. Users []*User `gorm:"many2many:user_languages;"`
11. }

Override Foreign Key

For a many2many relationship, the join table owns the foreign key which references two models, for example:

1. type User struct {
2. gorm.Model
3. Languages []Language `gorm:"many2many:user_languages;"`
4. }

6. type Language struct {
7. gorm.Model
8. Name string
9. }

11. // Join Table: user_languages
12. //   foreign key: user_id, reference: users.id
13. //   foreign key: language_id, reference: languages.id

To override them, you can use tag foreignKey, references, joinForeignKey, joinReferences, not necessary to use them together, you can just use one of them to override some foreign keys/references

1. type User struct {
2. gorm.Model
3. Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;joinReferences:ProfileRefer"`
4. Refer    uint      `gorm:"index:,unique"`
5. }

7. type Profile struct {
8. gorm.Model
9. Name      string
10. UserRefer uint `gorm:"index:,unique"`
11. }

13. // Which creates join table: user_profiles
14. //   foreign key: user_refer_id, reference: users.refer
15. //   foreign key: profile_refer, reference: profiles.user_refer

NOTE: Some databases only allow create database foreign keys that reference on a field having unique index, so you need to specify the unique index tag if you are creating database foreign keys when migrating

Self-Referential Many2Many

Self-referencing many2many relationship

1. type User struct {
2. gorm.Model
3. Friends []*User `gorm:"many2many:user_friends"`
4. }

6. // Which creates join table: user_friends
7. //   foreign key: user_id, reference: users.id
8. //   foreign key: friend_id, reference: users.id

Eager Loading

GORM allows eager loading has many associations with Preload, refer Preloading (Eager loading) for details

CRUD with Many2Many

Please checkout Association Mode for working with many2many relations

Customize JoinTable

JoinTable can be a full-featured model, like having Soft Delete,Hooks supports and more fields, you can setup it with SetupJoinTable, for example:

NOTE: Customized join table’s foreign keys required to be composited primary keys or composited unique index

1. type Person struct {
2. ID        int
3. Name      string
4. Addresses []Address `gorm:"many2many:person_addresses;"`
5. }

7. type Address struct {
8. ID   uint
9. Name string
10. }

12. type PersonAddress struct {
13. PersonID  int `gorm:"primaryKey"`
14. AddressID int `gorm:"primaryKey"`
15. CreatedAt time.Time
16. DeletedAt gorm.DeletedAt
17. }

19. func (PersonAddress) BeforeCreate(db *gorm.DB) error {
20. // ...
21. }

23. // Change model Person's field Addresses' join table to PersonAddress
24. // PersonAddress must defined all required foreign keys or it will raise error
25. err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})

FOREIGN KEY Constraints

You can setup OnUpdate, OnDelete constraints with tag constraint, it will be created when migrating with GORM, for example:

1. type User struct {
2. gorm.Model
3. Languages []Language `gorm:"many2many:user_speaks;"`
4. }

6. type Language struct {
7. Code string `gorm:"primarykey"`
8. Name string
9. }

11. // CREATE TABLE `user_speaks` (`user_id` integer,`language_code` text,PRIMARY KEY (`user_id`,`language_code`),CONSTRAINT `fk_user_speaks_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE,CONSTRAINT `fk_user_speaks_language` FOREIGN KEY (`language_code`) REFERENCES `languages`(`code`) ON DELETE SET NULL ON UPDATE CASCADE);

You are also allowed to delete selected many2many relations with Select when deleting, checkout Delete with Select for details

Composite Foreign Keys

If you are using Composite Primary Keys for your models, GORM will enable composite foreign keys by default

You are allowed to override the default foreign keys, to specify multiple foreign keys, just separate those keys’ name by commas, for example:

1. type Tag struct {
2. ID     uint   `gorm:"primaryKey"`
3. Locale string `gorm:"primaryKey"`
4. Value  string
5. }

7. type Blog struct {
8. ID         uint   `gorm:"primaryKey"`
9. Locale     string `gorm:"primaryKey"`
10. Subject    string
11. Body       string
12. Tags       []Tag `gorm:"many2many:blog_tags;"`
13. LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
14. SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
15. }

17. // Join Table: blog_tags
18. //   foreign key: blog_id, reference: blogs.id
19. //   foreign key: blog_locale, reference: blogs.locale
20. //   foreign key: tag_id, reference: tags.id
21. //   foreign key: tag_locale, reference: tags.locale

23. // Join Table: locale_blog_tags
24. //   foreign key: blog_id, reference: blogs.id
25. //   foreign key: blog_locale, reference: blogs.locale
26. //   foreign key: tag_id, reference: tags.id

28. // Join Table: shared_blog_tags
29. //   foreign key: blog_id, reference: blogs.id
30. //   foreign key: tag_id, reference: tags.id

Also check out Composite Primary Keys