I'm very new to Golang as I mostly code in Python, so came across one problem that I'm not able to solve. I want to add choices to a field in Golang Struct via GORM or any other way if I can achieve that.
My model looks like this
type User struct{
FirstName string `gorm:"size:100" json:"first_name"`
LastName string `gorm:"size:100" json:"last_name"`
Email *string `gorm:"size:250;index;not null;index:email;unique" json:"email"`
Role string `gorm:"default:User;not null" json:"is_active"` // TODO Add Choice
}
I want to add choices to my Role Field in User Models from ['Admin', 'User', 'Guest']. Is there a way to achieve it using GORM or any other method that will solve my problem? I can make it a Foreign key if there is no direct way to do it. I'm using PostgreSQL to store tables. Thanks in Advance!
Assuming you have a one-to-one relation between roles and users, one approach with the foreign keys would be something like this:
type User struct{
ID int64 `json:"id"`
FirstName string `gorm:"size:100" json:"first_name"`
LastName string `gorm:"size:100" json:"last_name"`
Email *string `gorm:"size:250;index;not null;index:email;unique" json:"email"`
RoleID int64 `json:"role_id"`
Role *Role `json:"role"`
}
type Role struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
//load data
var users []User
err := db.Preload("Role").Find(&users).Error
EDIT: solution for many-to-many
relationship
Assuming that you would have a table like users_roles that links the users and roles tables, one solution might look like this:
type User struct{
ID int64 `json:"id"`
FirstName string `gorm:"size:100" json:"first_name"`
LastName string `gorm:"size:100" json:"last_name"`
Email *string `gorm:"size:250;index;not null;index:email;unique" json:"email"`
Roles []*Role `gorm:"many2many:users_roles;" json:"roles"`
}
type Role struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
//load data
var users []User
err := db.Preload("Roles").Find(&users).Error
For PostGreSQL First create enum manually in your database
CREATE TYPE user_access AS ENUM (
'admin',
'user'
);
Then
type Role string
const (
Admin Role = "admin"
User Role = "user"
)
func (r *Role) Scan(value interface{}) error {
*r = Role(value.([]byte))
return nil
}
func (r Role) Value() (driver.Value, error) {
return string(r), nil
}
type User struct{
ID int64 `json:"id"`
FirstName string `gorm:"size:100" json:"first_name"`
LastName string `gorm:"size:100" json:"last_name"`
Email *string `gorm:"size:250;index;not null;index:email;unique" json:"email"`
Role Role `sql:"type:user_access"` // PostGreSQL
Role Role `json:"role" sql:"type:ENUM('admin', 'user')"` // MySQL
}
For more info you can check github issue and doc
Related
im a beginner in golang. when im using gorm:"primaryKey"
i dont see any field that use primary key
this is my model
type Orders struct {
OrderID uint64 `gorm:"primaryKey" json:"orderId"`
CustomerName string `json:"customerName"`
OrderedAt time.Time `json:"orderedAt" example:"2020-01-09T21:21:46+00:00"`
Items []Items `json:"items"`
}
type Items struct {
ItemID uint64 `gorm:"primaryKey" json:"lineItemId"`
Item_code string `json:"itemCode"`
Description string `json:"description"`
Quantity int `json:"quantity"`
}
which part do i wrong?
and do i need relational database for items field?
Lets be clear over here,
At first you need to declare a struct as a Model i.e by
type Anything struct {
gorm.Model
... (other fields)
}
And then in order to use Has Many relation you need to use the ID of the parent on the child i.e
type User struct {
gorm.Model
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint (like this over here.)
}
Please do kindly follow the docs GORM Docs
In the model Orders model has a hasMany relation to Items, but Items is missing the Key of Orders.
The db.AutoMigrate(&models.Orders{}, &models.Items{}) should be failing to create in this case for Order.Items, but the error is ignored.
Include OrdersID in Items struct to complete referential integrity because gorm expects default primary key/ foreign key as <StructName>ID so for Orders it will search OrdersID in Items
type Orders struct {
OrdersID uint64 `gorm:"primaryKey" json:"orderId"`
...
}
type Items struct {
OrdersID uint64
...
}
Suggestion, structs should be called Order and Item rather than Orders and Items thus the model becomes
type Order struct {
OrderID uint64 `gorm:"primaryKey" json:"orderId"`
CustomerName string `json:"customerName"`
OrderedAt time.Time `json:"orderedAt" example:"2020-01-09T21:21:46+00:00"`
Items []Item `json:"items"`
}
type Item struct {
ItemID uint64 `gorm:"primaryKey" json:"lineItemId"`
Item_code string `json:"itemCode"`
Description string `json:"description"`
Quantity int `json:"quantity"`
OrderID uint64
}
I'm working on a Gin app using Gorm ORM (I'm new to both of them). I've got the following model:
type Record struct {
Barcode string `json:"barcode" gorm:"size:48;unique;not null" sql:"index"`
Name string `json:"name" gorm:"size:160;unique;not null"`
Artist Artist `gorm:"foreignKey:ArtistID""`
ArtistId uint
Category Category `gorm:"foreignKey:CategoryID"`
CategoryId uint
NumOfRecords int `json:"num_of_records" gorm:"not null"`
OriginalReleaseDate time.Time `json:"original_release_date" gorm:"default:null"`
ReissueReleaseDate time.Time `json:"reissue_release_date" gorm:"default:null"`
SideColor string `json:"side_color" gorm:"default:null"`
BarcodeInRecord bool `json:"barcode_in_record" gorm:"default=true"`
gorm.Model
}
As you can see there are two fields with two foreign keys: Artist and Category.
Here's those models:
type Category struct {
Name string `json:"name" gorm:"size:60;unique;not null"`
Description string `json:"description" gorm:"size:120"`
Parent uint `json:"parent" gorm:"default:null"`
Active bool `json:"active" gorm:"default:true"`
gorm.Model
}
type Artist struct {
Name string `json:"name" gorm:"size:120;unique;not null"`
Type string `json:"type" gorm:"default:null"`
CountryOfOrigin string `json:"countryOfOrigin" gorm:"default:null"`
gorm.Model
}
category_id and artist_id columns are being created but they are not referencing the other tables two tables:
I've tried to define those fields using AssociationForeignKey:Refer. I also tried to change the foreign key name to simply ID since that's the name that GORM assigns to primary keys but none of those thinks have worked.
What am I missing?
IMO Gorm docs are pretty lousy. From another SO question (Gorm Golang orm associations) it is said that:
it doesn't (create FKs when migrations run). If you want Foreign Key in DB, you need explicitly write something like db.Model(&Place{}).AddForeignKey("town_id", "towns(id)", "RESTRICT", "RESTRICT") during your migrations.
I have a TODO list application which is based on items and users. When I get a user from the users collection in mongo, I also want to get the items with the field "userId" which are in another collection. But all this should happen in one query. I want to know how should I emulate the joins from SQL or some method which can return all that I requiring in one query. I only get the id of the user in repository.
Here is the code:
Item
type Item struct{
ItemId primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
Title string `bson:"title,omitempty" json:"title"`
Description string `bson:"description,omitempty" json:"description"`
UserId primitive.ObjectID `bson:"userId" json:"userId"`
}
func NewItem(title string,description string) Item {
return Item{
Title: title,
Description: description,
}
}
User
type User struct{
UserId primitive.ObjectID `bson:"_id,omitempty" json:"user_id"`
UserName string `bson:"name,omitempty" json:"user_name"`
Status bool `bson:"status" json:"status"`
Items []Item `bson:"items" json:"items"`
}
func NewUser(userId primitive.ObjectID,userName string,status bool,items []Item) User{
return User{
userId,
userName,
status,
items,
}
}
I have the following table schema:
user
-----
id uuid
name string
user_model
------
id uuid
user_id uuid
model_id uuid
role int
model
_____
id uuid
name string
model_no string
I have the following code which fetches the data from the "model" table.
underlyingModel = &model{}
var model IModel
model = underlyingModel
role := 0
db.Table("model").Joins('INNER JOIN user_model ON user.id = user_model.uuid')
.Joins('INNER JOIN model ON user.id = model_id').Find(&model);
In my actual code, the model can be many different struct types with different fields, they're all behind the IModel interface.
What I want to do is to fetch that extra role field from the user_model in one query. Something like .Find(&model, &role).
Is it possible using Gorm?
One possible solution is to create an anonymous struct to put the results in, with a combination of the Select() method.
var selectModel struct {
ID string //I'm assuming uuid matches the string
Name string
ModelNo string
Role int
}
db.Table("model").
Joins("INNER JOIN user_model ON user.id = user_model.uuid").
Joins("INNER JOIN model ON user.id = model_id").
Select("model.id, model.name, model.model_no, user_model.role").
Find(&selectModel);
Basically, you create an anonymous struct with selectModel variable, containing all the fields you want to return. Then, you need to do a select statement because you need some fields that are not part of the model table.
Here you can find more info on Smart Select Fields in form.
EDIT:
Based on additional info from the comments, there is a solution that might work.
Your IModel interface could have two methods in its signature, one to extract a string for the SELECT part of the SQL query, and the other one to get a pointer of the selectModel that you would use in the Find method.
type IModel interface {
SelectFields() string
GetSelectModel() interface{}
}
The implementation would go something like this:
func (m *model) SelectFields() string {
return "model.id, model.name, model.model_no, user_model.role"
}
func (m *model) GetSelectModel() interface{} {
return &m.selectModel
}
type model struct {
selectModel
ID uint64
Age int
}
type selectModel struct {
Name string
Email string
}
Then, your query could look something like this:
var m IModel
m = model{}
db.Table("model").
Joins("INNER JOIN user_model ON user.id = user_model.uuid").
Joins("INNER JOIN model ON user.id = model_id").
Select(m.GetSelectFields()).
Find(m.GetSelectModel());
I have the following scenario:
type Band struct {
Name string
LocationId *datastore.Key
Albums []Album
}
type Album struct {
Name string
GenreId *datastore.Key
Year int
}
What I want to do is query a Bands Albums key for an album with a specific GenreId key.
I found the answer. It turned out to be simple. Instead of
Filter("GenreId =", genreId)
I used
Filter("Albums.GenreId =", genreId)
That gave me valid query results.