gorm many2many relationships not working, can't preload field - go

I'm building an api to learn more from Go and I'm having a problem with the many to many relationship between 2 entities.
I have 2 models
type Patient struct {
ID uint `json:"id" gorm:"primary_key"`
Name string `json: "name"`
Surname string `json: "surname"`
Cellphone int `json: "cellphone"`
Email string `json: "email"`
Professionals []*Professional `json: "professionals" gorm:"many2many:professional_patient"`
}
and
type Professional struct {
ID uint `json:"id" gorm:"primary_key"`
Name string `json:"name"`
Surname string `json:"surname"`
Cellphone int `json:"cellphone"`
AuxiliarCellphone int `json:"auxiliarCellphone"`
Email string `json:"email"`
Patients []*Patient `json:"patients" gorm:"many2many:professional_patient"`
}
and the get functions are
func GetAllPatients(c *gin.Context) {
var patients []models.Patient
internal.DB.Preload("Professionals").Find(&patients)
c.JSON(http.StatusOK, gin.H{"data": patients})
}
and
func GetAllProfessionals(c *gin.Context) {
var professionals []models.Professional
internal.DB.Preload("Patients").Find(&professionals)
c.JSON(http.StatusOK, gin.H{"data": professionals})
}
when i make a get request in postman for the professionals, the patients field return an empty array (which i think is fine because they don't have any patient loaded yet)
but in the case of the patients they return a "null" in the professionals field and the log in vscode says:
[2020-07-10 02:04:52] can't preload field Professionals for models.Patient
What can I do here?

Related

Is it possible to use many to many between 3 models? (GORM)

Is it possible to use many to many between 3 models?
I have 3 models I want to join into a bridge table "client_operator_role"
Operator
type Operator struct {
gorm.Model
Title string `gorm:"unique;not null" validate:"required,min=1,max=100"`
Email string `gorm:"not null;unique" validate:"required,email"`
Mobile string `gorm:"not null" validate:"required,min=7,max=15,numeric"`
Last_online time.Time `gorm:"default:null" validate:"omitempty"`
Last_ip string `gorm:"default:null" validate:"omitempty,ip"`
Clients []*Client `gorm:"many2many:client_operator_role;"`
Cli_ids []string `gorm:"-:all" validate:"omitempty,dive,numeric"` // placeholder field, wont be part of table
GoadminCustomUser GoadminCustomUser `validate:"omitempty,dive"`
}
Client
type Client struct {
gorm.Model
Name string `gorm:"unique;not null" validate:"required,min=1,max=30"`
Kyc_status string `gorm:"not null" validate:"required,min=1,max=30"`
Kyc_remarks string `gorm:"default:null" validate:"omitempty,min=0,max=200"`
Operators []*Operator `gorm:"many2many:client_operator_role;"`
Op_ids []string `gorm:"-:all" validate:"omitempty,dive,numeric"` // placeholder field, wont be part of table
Users []User
}
Role
type GoadminRole struct {
ID uint `gorm:"primaryKey"`
Name string
Slug string
CreatedAt time.Time
UpdatedAt time.Time
Operators []*Operator `gorm:"many2many:client_operator_role;"`
}
Gorm docs state many2many is only for 2 models. Is there a workaround to join these three?

How to append custom attribute to Golang struct like $append on a Laravel model?

I am trying to add a custom attribute to my Golang struct just like how I usually add custom attribute on a Laravel model using the $appends variable.
This is the code:
package models
import (
"time"
)
type Dummy struct {
ID string `json:"id" gorm:"primary_key"`
Description string `json:"description"`
Image string `json:"image"`
ImageUrl ImageUrlDummy
Number int `json:"number"`
UserId string `json:"user_id"`
User User `json:"user"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func ImageUrlDummy() string {
return "test"
}
However, the ImageUrlDummy inside the struct does not work, it return error such as:
ImageUrlDummy (value of type func() string) is not a type
How do I achieve this same code from Laravel to Golang?
class Dummy extends Model
{
protected $appends = ['image_url'];
public function getImageUrlAttribute(){
return "this is the image url";
}
}
Please pardon me I am still learning Golang, thank you
You are not far off..
Change your struct to (remove ImageUrlDummy, fix json tag for Image):
type Dummy struct {
ID string `json:"id" gorm:"primary_key"`
Description string `json:"description"`
Image string `json:"image"`
Number int `json:"number"`
UserId string `json:"user_id"`
User User `json:"user"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Then define a method with a receiver of type Dummy pointer
func (d *Dummy) ImageUrl() string {
return "test"
}
Example with a few more things: https://play.golang.com/p/olGSFhBgqkG

how query to ManyToMany field in gorm

I'm using gorm to handle database queries and I have 2 models (ManyToMany) :
type Person struct {
ID uint `json:"id" gorm:"primary_key;unique;autoIncrement"`
Name string `json:"name" binding:"required"`
Family string `json:"family" binding:"required"`
Companies []Company `json:"companies" gorm:"many2many:person_companies;"`
}
type Company struct {
ID uint `json:"id" gorm:"primary_key;unique;autoIncrement"`
Name string `json:"name"`
cars []Car
}
i use this query for receive list of my users:
func GetAllPeople() *[]domain.Person {
var people []domain.Person
db.Find(&people)
return &people
}
this works but shows me Null for companies
{
"id": 0,
"name": "erfan",
"family": "",
"companies": null
}
what should I use in query to show users companies (id) in a list?
You will have to use the Preload method with custom loading to just load the company ID's into the Companies field.
func GetAllPeople() *[]domain.Person {
var people []domain.Person
tx := db.Preload("Companies", func(db *gorm.DB) *gorm.DB {
return db.Select("ID")
}).Find(&people)
if tx.Error != nil {
// handle error
}
return &people
}
You can find more details on this link or this question.

go-pg got doesn't has relation thought on my table has relation

i have a contacts relation to provinces, and here is on my struct
Contact struct {
tableName struct{} `pg:"contacts,discard_unknown_columns"`
ID int `json:"id"`
Address string `json:"address"`
BuildingType string `json:"building_type"`
BuildingNumber float64 `json:"building_number"`
Province *Province `pg:"fk:province_id" json:"province"`
}
Province struct {
tableName struct{} `pg:"provinces,discard_unknown_columns"`
ID int `json:"id" pg:",pk"`
Name string `json:"name"`
}
and here how i call:
var us Contact
err = db.Model(&us).Relation("provinces").Where(
"id = ?", 3,
).Select()
what i go is model=Contact does not have relation="provinces"
how to correct way to query this with go-pg?
when i change tag on Contact for Province with tag pg:"rel:has-one"
i got this error
pg: Contact has-one Province: Contact must have column province_id (use fk:custom_column tag on Province field to specify custom column)
note: i dont use their migration, i use sql-migration for all migrations
As stated in the error and the docs, you need to have a province_id column on Contact:
Contact struct {
tableName struct{} `pg:"contacts,discard_unknown_columns"`
ID int `json:"id"`
Address string `json:"address"`
BuildingType string `json:"building_type"`
BuildingNumber float64 `json:"building_number"`
ProvinceId int
Province *Province `pg:"rel:has-one" json:"province"`
}
If your ref column name is not province_id then you can use another column and add fk:custom_column to it.
Your province is missing a foreign key, try this I think it will work.
Contact struct {
tableName struct{} `pg:"contacts,discard_unknown_columns"`
ID int `json:"id"`
Address string `json:"address"`
BuildingType string `json:"building_type"`
BuildingNumber float64 `json:"building_number"`
Province *Province `pg:"fk:contact_id" json:"province"`
}
Province struct {
tableName struct{} `pg:"provinces,discard_unknown_columns"`
ID int `json:"id" pg:",pk"`
Name string `json:"name"`
ContactID int `pg:"on_delete:CASCADE,notnull"`
}

How to solve gorm many2many error1062

I have a many2many relation between news and tag. Whenever I tried to assign news to a tag it gives me an error Error 1062: Duplicate entry '5' for key 'news_id'
My model look like this:
type Tag struct {
ID uint64 `json:"id" gorm:"primary_key;unique;AUTO_INCREMENT"`
Title string `json:"title" gorm:"varchar(20)" binding:"required"`
News []*News `json:"news" gorm:"many2many:news_tags;association_foreignkey:ID;foreignkey:ID"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
}
// News model
type News struct {
ID uint64 `json:"id" gorm:"primary_key;unique;AUTO_INCREMENT"`
Title string `json:"title" gorm:"varchar(20)" binding:"required"`
Body string `json:"body" gorm:"varchar(500)" binding:"required"`
Status string `json:"status" gorm:"varchar(5)"` // 1 = publish; 2 = draft; 3 = deleted;
Tags []*Tag `json:"tags" gorm:"many2many:news_tags;association_foreignkey:ID;foreignkey:ID"`
Topics []*Topic `json:"topics" gorm:"many2many:news_topics"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
}
// My code when trying to assign new tag
func (n *News) AssignTags(tag Tag) {
db.DB().Model(n).Association("Tags").Append(tag)
}

Resources