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.
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)