Search code examples
postgresqlgoormgo-gorm

Is it possible to defining multiple relationships between two tables in Gorm?


I'm building a simple app for users to add songs to a list, and to vote on songs, and I'm building the backend in Go, using Gorm with a Postgres database.

Here are my structures:

type User struct {
    gorm.Model
    Name        string `json:"name"`        // Name of user
    DisplayName string `json:"displayName"` // Display name of user
    Password    string `json:"password"`    // Password
    SongsAdded  []Song `json:"songs"`       // Songs added by user
}

type Song struct {
    gorm.Model
    Title    string `json:"title"`    // Song title
    Artist   string `json:"artist"`   // Song artist
    ImageURL string `json:"imageUrl"` // URL to image
    UserId   uint   `json:"userId"`   // ID of user that added the song
    Likes    []User `json:"likes"`    // List of users that like the song
    Dislikes []User `json:"dislikes"` // List of users that dislike the song
}

I'd like to keep track of which user added a song to the list (hence the SongsAdded field in the User struct, and the UserId field in the Song struct). To keep track of the votes, I'd like to add users to either the Likes or Dislikes User slices in the Song struct. However, I'm getting this error when I try to AutoMigrate:

invalid field found for struct main.Song's field Likes: define a valid foreign key for relations or implement the Valuer/Scanner interface

I imagine that I am confusing Gorm by having three different references to User in the same struct, but I am not quite sure how to address this. I suppose I could change Likes and Dislikes to slices of string or uint and put usernames or user IDs there instead, but I'd be happier if the reference was to the actual objects so I don't have to perform additional DB searches.

Any suggestions on how to either redesign my data structures, or configure them properly so that this will work?

Using the above structures, I tried running db.AutoMigrate(&User{}, &Song{}) but I am getting an error when the Likes field is reached, and the Song DB table is not created.

I expected both tables to be created without errors.


Solution

  • You need to define the many to many relationship (each song can have many users who liked/disliked, each user can like/dislike many songs):

    type User struct {
        gorm.Model
        Name        string `json:"name"`        // Name of user
        DisplayName string `json:"displayName"` // Display name of user
        Password    string `json:"password"`    // Password
        SongsAdded  []Song `json:"songs"`       // Songs added by user
        Likes       []Song `json:"likes" gorm:"many2many:user_likes;"`    // List of songs that this user likes
        Dislikes    []Song `json:"dislikes" gorm:"many2many:user_dislikes;"` // List of songs that this user dislikes
    

    } }

    type Song struct {
        gorm.Model
        Title    string `json:"title"`    // Song title
        Artist   string `json:"artist"`   // Song artist
        ImageURL string `json:"imageUrl"` // URL to image
        UserId   uint   `json:"userId"`   // ID of user that added the song
        Likes    []User `json:"likes" gorm:"many2many:user_likes;"`    // List of users that like the song
        Dislikes []User `json:"dislikes" gorm:"many2many:user_dislikes;"` // List of users that dislike the song
    }
    

    see https://gorm.io/docs/many_to_many.html

    And then you'll need to do something like

    db.Preload("Likes").Preload("Dislikes").Load(&user)