using smart select in gorm with many 2 many relation - go

I want to use smart select when querying rooms table. When use the original struct it works fine but when use smart select it fails.
Here is my schema
type Room struct {
gorm.Model
ID uint `json:"id" gorm:"primary_key"`
Hash string `json:"hash" binding:"required" gorm:"not null:true"`
Users []User `json:"users" gorm:"many2many:room_users"`
Messages []Message `json:"messages"`
}
type RoomAPI struct {
ID uint `json:"id" gorm:"primary_key"`
Hash string `json:"hash" binding:"required" gorm:"not null:true"`
Users []User `json:"users" gorm:"many2many:room_users"`
//Messages []Message `json:"messages" gorm:"foreignKey:RoomID"`
}
func (RoomAPI) TableName() string {
return "rooms"
}
type User struct {
gorm.Model
ID uint `json:"id" gorm:"primary_key"`
Name string `json:"name" binding:"required" gorm:"not null:true"`
Phone string `json:"phone"`
Email string `json:"email" binding:"required,email" gorm:"not null:true"`
Password string `json:"password" binding:"required,min=8" gorm:"not null:true"`
Gender string `json:"gender" binding:"Enum=male_female" gorm:"type:gender;not null:true;default:male"`
Rooms []Room `json:"rooms" gorm:"many2many:room_users"`
}
type Message struct {
gorm.Model
ID uint `json:"id" gorm:"primary_key"`
Text string `json:"text" binding:"required" gorm:"not null:true"`
UserID uint `json:"user_id" gorm:"not null:true"`
RoomID uint `json:"room_id" gorm:"not null:true"`
}
here is my query
var rooms []RoomAPI
user := User{ID: userId}
err := db.DB.Model(&user).Preload("Users").
Association("Rooms").
Find(&rooms)
if err != nil {
log.Printf("err -> %+v", err)
return err, nil
}
return nil, rooms
I want to get rooms with selected fields with smart select but it fails

Related

invalid field found for struct models.User's field Identities: define a valid foreign key for relations or implement the Valuer/Scanner interface

Always got an error when I add the relationship to the User in GitUser struct.
type GitUser struct {
ID uint `json:"id" gorm:"primaryKey"`
ExternalID string
JobID uint
UserID uint
User User `gorm:"foreignKey:UserID;references:ID"`
Job Job `gorm:"foreignKey:JobID;references:ID"`
}
type User struct {
ID uint `json:"id" gorm:"primaryKey"`
ExternalId *string
Username string
Email string
Name string
HashedPassword *string
AvatarUrl *string
IsAdmin bool
LastSignInAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
IsArchived bool
GitUser []GitUser
}
I'm trying to make a mutual relationship between User and GitUser

Golang Gorm BackReference

So I have two structs User and Company which are as follows
//Company
type Company struct {
Id int `json:"id" gorm:"primaryKey;autoIncrement;type:int"`
Poc_name string `json:"poc_name" gorm:"type:string;size:128;not null"`
Poc_title string `json:"poc_title" gorm:"type:string;size:255;not null"`
Poc_email string `json:"poc_email" gorm:"type:string;size:128;not null"`
Poc_phone string `json:"poc_phone" gorm:"type:string;size:128;not null"`
Default_driver_commission float32 `json:"default_driver_commission" gorm:"type:float;default:12;not null"`
Mc_number string `json:"mc_number" gorm:"type:string;size:128;default:null"`
Us_dot_number string `json:"us_dot_number" gorm:"type:string;size:128;default:null"`
Fk_user_id int `json:"fk_user_id" gorm:"not null;type:int"`
Fk_user Users `json:"user" gorm:"foreignKey:Fk_user_id"`
Time_created time.Time `json:"time_created" gorm:"autoCreateTime;not null"`
Time_updated time.Time `json:"time_updated" gorm:"autoCreateTime;not null"`
}
//User
type Users struct {
Id int `json:"id" gorm:"primaryKey;autoIncrement;type:int"`
Username string `json:"username" gorm:"unique;not null;type:string;size:128"`
Email string `json:"email" gorm:"unique;not null;type:string;size:128"`
Password string `gorm:"not null;type:string;size:255"`
Phone string `json:"phone" gorm:"not null;type:string;size:128"`
First_name string `json:"first_name" gorm:"not null;type:string;size:128"`
Last_name string `json:"last_name" gorm:"not null;type:string;size:128"`
Provider string `json:"provider" gorm:"not null;type:string;size:128"`
Profile_picture_url string `json:"profile_picture_url" gorm:"type:text"`
Is_verified bool `json:"is_verified" gorm:"default:true;not null"`
Stripe_id string `json:"stripe_id" gorm:"not null;type:string;size:350"`
Fcm_token string `json:"fcm_token" gorm:"not null;type:string;size:350"`
Web_fcm_token string `json:"web_fcm_token" gorm:"not null;type:string;size:350"`
Hour_format_12 bool `json:"hour_format_12" gorm:"not null;default:false"`
Temp_in_centi bool `json:"temp_in_centi" gorm:"not null;default:false"`
Map_pref string `json:"map_pref" gorm:"not null;type:string;size:350"`
Time_created time.Time `json:"time_created" gorm:"autoCreateTime;not null"`
Time_updated time.Time `json:"time_updated" gorm:"autoCreateTime;not null"`
User_type int `json:"user_type" gorm:"not null"`
Address_id int `json:"address_id" gorm:"not null"`
Fk_address Address `json:"address" gorm:"foreignKey:Address_id"`
}
And this is my api call
func GetUserById(c *fiber.Ctx) error {
id, err := c.ParamsInt("id")
// var user models.Company
var user models.Users
if err != nil {
return c.Status(400).JSON("Please Ensure that :id is an integer")
}
// database.Database.Db.Preload("Fk_user.Fk_address").Where("Fk_user_id = ?", id).Find(&user)
database.Database.Db.Preload("Fk_address").Find(&user, id)
if user.Id == 0 {
return c.Status(404).JSON("User Does Not Exists")
}
// log.Fatalln(responseuser.Fk_address)
return c.Status(200).JSON(&user)
}
How can I access the company object from the user object. Previously we using Flask and SQAlchemy and it was made possible by back_ref. Is there anything similar in Gorm and Fiber ? thanks

Golang Gorm retrive one to many relation with limit

Hello I have Room and Messages tables where where room has many messages. I want to get user rooms with limit 20 rooms and each room has only 20 messages only.
type Room struct {
gorm.Model
ID uint `json:"id" gorm:"primary_key"`
Hash string `json:"hash" binding:"required" gorm:"not null:true"`
Users []User `json:"users" gorm:"many2many:room_users"`
Messages []Message `json:"messages"`
Blocked bool `json:"blocked" gorm:"default:false"`
BlockerId uint `json:"blocker_id" gorm:"nullable:true"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
RoomBotData shared.RoomBotData `json:"bot_data"`
RoomBotDataID uint `json:"room_bot_data_id"`
}
type Message struct {
ID uint `json:"id" gorm:"primary_key"`
Text string `json:"text" binding:"required" gorm:"not null:true"`
UserID uint `json:"user_id" gorm:"not null:true"`
RoomID uint `json:"room_id" gorm:"not null:true"`
IsRead bool `json:"is_read" binding:"required" gorm:"default:false"`
Type string `json:"type" gorm:"default:text"`
CreatedAt time.Time `json:"created_at"`
}
I have tried preload function and set limit to 20 for message
db.Preload("Messages", func(db *gorm.DB) *gorm.DB {
return db.Limit(20)
}).Find(&rooms)
but this only get 20 messages in total for all rooms.
I also tried to get 20 messages for each room
err = db.DB.Model(&Room{}).
Order("updated_at DESC").
Limit(20).
Preload(RoomSchema.Users).
Where("id in ?", roomIds).
Find(&rooms).Error
roomMessagesChannel := make(chan map[int][]Message)
for i, room := range rooms {
go r.getRoomMessages(roomMessagesChannel, room.ID, i)
}
for i := 0; i < len(rooms); i++ {
messagesMap := <-roomMessagesChannel
firstItemOfMap := reflect.ValueOf(messagesMap).MapKeys()[0].Int()
rooms[int(firstItemOfMap)].Messages = messagesMap[int(firstItemOfMap)]
}
close(roomMessagesChannel)
I used channels to speed up the process but it cause memory leak and consume a lot of memory. I want to do that in a better way

Gorm UUID foreign key - belongs to

I'm trying to create a belongs to relation between two database tables, using GORM, my code is the following:
type Shop struct {
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
Name string `json:"name" gorm:"not null" validate:"required"`
City string `json:"city" gorm:"not null" validate:"required"`
State string `json:"state" gorm:"not null" validate:"required"`
}
type Employee struct {
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid"`
FirstName string `json:"first_name" gorm:"not null" validate:"required"`
LastName string `json:"last_name" gorm:"not null" validate:"required"`
Email string `json:"email" gorm:"not null;unique" validate:"required,email"`
Password string `json:"password" gorm:"not null" validate:"required"`
Active bool `json:"active" gorm:"not null;default:false"`
ShopId uuid.UUID `json:"shop_id" gorm:"type:uuid"`
Shop Shop `gorm:"foreignKey:ShopID"`
}
When I run the migrations, this error pops up:
[error] invalid field found for struct .../.../.../api/models.Employee's field Shop: define a valid foreign key for relations or implement the Valuer/Scanner interface
I've found some references using number primary keys and they seem to work fine, but I can't find any solution to work with uuids...
I'm not sure, but what I understand of the message error is that the type uuid.UUID doesn't have implemented the methods for the interfaces Valuer and Scanner.
You should create your own type UUID, which can be something like this:
type UUID uuid.UUID
func(id UUID) Value() (driver.Value, error) {
return id.String(), nil
}
func (id *UUID) Scan(value interface{}) error {
dbID, ok := value.(string)
if !ok {
return errors.New("id scan: invalid value")
}
*e = uuid.MustParse(dbID)
return nil
}
And use it on your struct's definitions:
type Shop struct {
ID UUID `json:"id" gorm:"primaryKey;type:uuid"`
//...
}

How to specify a model to model association but without any dependency?

i got two models in GORM as following:
type (
Todo struct {
gorm.Model
EventId int64 `json:"event_id" form:"event_id" binding:"required"`
UserId uint `json:"user_id" form:"user_id"`
DoneUserId uint `json:"done_user_id" form:"done_user_id"`
Groups string `json:"groups" form:"groups"`
DoneAt *time.Time `json:"done_at" form:"done_at"`
TodoEnd time.Time `json:"todo_end" form:"todo_end" binding:"required"`
Priority uint `json:"priority" form:"priority" binding:"required"`
Done bool `json:"done" form:"done"`
Title string `json:"title" form:"title" binding:"required"`
Description string `json:"description" form:"description"`
CreatorId uint `json:"creator_id"`
ChangerId uint `json:"changer_id"`
Event Event
}
)
and
type (
Event struct {
gorm.Model
CustomerId uint `json:"customer_id" form:"customer_id" binding:"required"`
AddressId uint `json:"address_id" form:"address_id" binding:"required"`
UserId uint `json:"user_id" form:"user_id"`
EventType string `json:"event_type" form:"event_type" binding:"required"`
ContactPerson string `json:"contact_person" form:"contact_person"`
Title string `json:"title" form:"title" binding:"required"`
Description string `gorm:"type:text" json:"description" form:"description"`
Calculated bool `json:"calculated" form:"calculated"`
Goodwill bool `json:"goodwill" form:"goodwill"`
Billable bool `json:"billable" form:"billable"`
EventBegin time.Time `json:"event_begin" form:"event_begin" binding:"required"`
EventEnd time.Time `json:"event_end" form:"event_end" binding:"required"`
PartsJson string `gorm:"type:text" json:"parts_json" form:"parts_json"`
FieldsJson string `gorm:"type:text" json:"fields_json" form:"fields_json"`
CreatorId uint `json:"creator_id"`
ChangerId uint `json:"changer_id"`
Todos []Todo
Customer Customer
}
)
When I save a new Todo with an event_id set, then I get many errors regarding empty fields within the event object. Thats right, because I do not fill the event object I just set the event_id in the todo object. So my question is, is there a way how I can disable these validations?
The association from Todo to Event is just for query reasons, that I get a nested Event-Object in Todo-Object - or better said I get the nested object in the json.
I would personally try do it like this:
type MinimalTodo struct {
gorm.Model
EventId int64 `json:"event_id" form:"event_id" binding:"required"`
UserId uint `json:"user_id" form:"user_id"`
DoneUserId uint `json:"done_user_id" form:"done_user_id"`
Groups string `json:"groups" form:"groups"`
DoneAt *time.Time `json:"done_at" form:"done_at"`
TodoEnd time.Time `json:"todo_end" form:"todo_end" binding:"required"`
Priority uint `json:"priority" form:"priority" binding:"required"`
Done bool `json:"done" form:"done"`
Title string `json:"title" form:"title" binding:"required"`
Description string `json:"description" form:"description"`
CreatorId uint `json:"creator_id"`
ChangerId uint `json:"changer_id"`
}
func (MinimalTodo) TableName() string {
return "todos"
}
type Todo struct {
MinimalTodo
Event
}
Not sure if it'll work with Gorm. Otherwise, I'd probably see how much work it would be to just change Event to a pointer:
type Todo struct {
gorm.Model
EventId int64 `json:"event_id" form:"event_id" binding:"required"`
UserId uint `json:"user_id" form:"user_id"`
DoneUserId uint `json:"done_user_id" form:"done_user_id"`
Groups string `json:"groups" form:"groups"`
DoneAt *time.Time `json:"done_at" form:"done_at"`
TodoEnd time.Time `json:"todo_end" form:"todo_end" binding:"required"`
Priority uint `json:"priority" form:"priority" binding:"required"`
Done bool `json:"done" form:"done"`
Title string `json:"title" form:"title" binding:"required"`
Description string `json:"description" form:"description"`
CreatorId uint `json:"creator_id"`
ChangerId uint `json:"changer_id"`
Event *Event
}

Resources