Marshalling and unmarshalling [closed] - go

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 12 hours ago.
Improve this question
I'm a golang intern and i have a question . I have a struct
package migrations
import (
"gorm.io/gorm"
)
type Service struct {
gorm.Model
CategoryId uint `json:"category_id"`
ProviderId uint `json:"provider_id"`
CategoryModel Category `gorm:"ForeignKey:category_id"`
ProviderModel Provider `gorm:"ForeignKey:provider_id"`
Uuid string `json:"uuid"`
Title string `json:"title"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
Unit string `json:"unit"`
PaymentType string `json:"payment_type"`
CityId int `json:"city_id"`
HotelId int `json:"hotel_id"`
GroupId int `json:"group_id"`
UserId int `json:"user_id"`
Status bool `json:"status"`
ServiceItems []serviceItem `gorm:"foreignKey:service_id"`
Pricing []ServicePricing `gorm:"foreignKey:service_id"`
Image []ServiceImage `gorm:"foreignKey:service_id"`
}
type serviceItem struct {
ServiceId uint `json:"service_id"`
ItemId uint `json:"item_id"`
Sort uint `json:"sort"`
Status bool `json:"status"`
}
which connect to database . also i have a struct which is my request:
package services
type Request struct {
ProviderId uint `json:"provider_Id" binding:"required"`
CategoryId uint `json:"category_id" binding:"required"`
Title string `json:"title" binding:"required"`
Unit string `json:"unit"`
PaymentType string `json:"payment_type"`
StartDate string `json:"start_date" binding:"required"`
EndDate string `json:"end_date" binding:"required"`
HotelId int `json:"hotel_id"`
GroupId int `json:"group_id"`
UserId int `json:"user_id"`
CityId int `json:"city_id" binding:"required"`
ServiceItems []ServiceItem `json:"service_items"`
}
type ServiceItem struct {
ItemId uint `json:"item_id"`
ServiceId uint `json:"service_id"`
Sort uint `json:"sort"`
}
when i use code blow request.serviceItem wont fill the migration.serviceItem
func Create(c *gin.Context) (error, Response) {
var req Request
var res Response
if e := c.ShouldBind(&req); e != nil {
return e, res
}
result, e := services.Create(req, req.ServiceItems)
if e != nil {
return e, res
}
err, resp := decoder(res, result)
if err != nil {
return err, resp
}
return nil, resp
}
//package services
func Create(req interface{}, items interface{}) (migrations.Service, error) {
var service migrations.Service
b, e := json.Marshal(req)
if e != nil {
return service, e
}
e = json.Unmarshal(b, &service)
if e != nil {
return service, e
}
result := migrations.DB.Model(migrations.Service{}).Create(&service)
if result.Error != nil {
return service, result.Error
}
return service, nil
}

Related

How to Update Multiple Records Using gorm?

So I want to update movie_genre data with different genre_id values, each movie has more than 1 genre_id automatically there are multiple records in movie_genre with the same movie_id and different genre_id,
when I start trying to update with gorm by selecting only 1 genre_id, the old genre has changed, but the newly changed genre is created again in a new row with all the same column values ​​except created_at, whereas if I try to update by selecting 2 genres, the data the changed only has the value of the first genre_id, the second genre_id is not read
this is a erd database
payload json from frontend
{
"title":"Autaaa sint nihil quis ",
"release_date":"2001-01-01",
"runtime":"22",
"mpaa_rating":"G",
"rating":"4",
"description":"Eius enim distinctio1",
"id":"82",
"genre_id":["3","8"]
}:
handler
func (app *Application) UpdateMovie(ctx *gin.Context) {
var payload web.MoviePayloadResponse
if err := ctx.BindJSON(&payload); err != nil {
log.Println(err)
return
}
id, _ := strconv.Atoi(payload.ID)
movie, err := app.models.Repository.GetMovieById(id)
if err != nil {
helper.NotFound(*ctx, err)
return
}
movie.ID, _ = strconv.Atoi(payload.ID)
movie.Title = payload.Title
movie.Description = payload.Description
movie.ReleaseDate, _ = time.Parse("2006-01-02", payload.ReleaseDate)
movie.Year = movie.ReleaseDate.Year()
movie.Runtime, _ = strconv.Atoi(payload.Runtime)
movie.Rating, _ = strconv.Atoi(payload.Rating)
movie.MPAARating = payload.MPAARating
movie.UpdatedAt = time.Now()
err = app.models.Repository.UpdateMovie(movie, id)
if err != nil {
panic(err)
}
movieGenre, _ := app.models.Repository.GetMovieGenresById(id)
for _, mg := range *movieGenre {
mg.MovieID = movie.ID
mg.UpdatedAt = time.Now()
for _, v := range payload.GenreID {
mg.GenreID, _ = strconv.Atoi(v)
err := app.models.Repository.UpdateMovieGenre(&mg, id)
if err != nil {
panic(err)
}
}
}
ctx.JSON(http.StatusOK, &gin.H{
"ok": "response",
})
return
}
repository
func (MovieRepositoryImpl *MovieRepositoryImpl) UpdateMovie(movie *Movie, id int) error {
err := MovieRepositoryImpl.DB.Where("id = ?", id).Save(&movie).Error
if err != nil {
return err
}
return nil
}
func (MovieRepositoryImpl *MovieRepositoryImpl) UpdateMovieGenre(movieGenre *MovieGenre, id int) error {
err := MovieRepositoryImpl.DB.Where("movie_id = ?", id).Save(&movieGenre).Error
if err != nil {
return err
}
return nil
}
func (MovieRepositoryImpl *MovieRepositoryImpl) GetMovieGenresById(id int) (*[]MovieGenre, error) {
var movie []MovieGenre
err := MovieRepositoryImpl.DB.Where("movie_id = ?", id).Find(&movie).Error
if err != nil {
return nil, err
}
return &movie, nil
}
Model
type Movie struct {
ID int `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Year int `json:"year"`
ReleaseDate time.Time `json:"release_date"`
Runtime int `json:"runtime"`
Rating int `json:"rating"`
MPAARating string `json:"mpaa_rating"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Genres []Genre `json:"genres" gorm:"many2many:movie_genres"`
MovieGenre []MovieGenre `json:"movie_genres" gorm:"many2many:movie_genres"`
}
type Genre struct {
ID int `json:"id"`
GenreName string `json:"name"`
Movies []Movie `json:"movies" gorm:"many2many:movie_genres"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
type MovieGenre struct {
ID int `json:"id"`
MovieID int `json:"movie_id"`
Movie Movie `gorm:"foreignKey:MovieID"`
GenreID int `json:"genre_id"`
Genre Genre `gorm:"foreignKey:GenreID"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
type MoviePayloadResponse struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Year string `json:"year"`
ReleaseDate string `json:"release_date"`
Runtime string `json:"runtime"`
Rating string `json:"rating"`
MPAARating string `json:"mpaa_rating"`
GenreID []string `json:"genre_id"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
My expectation is that the data genre_id that changes is only data whose value is not the same as the value in the payload, if it is the same then the data does not change, if it is different then it changes, and if the data in the payload exceeds the original genre data, then new data is automatically created. That's roughly what it looks like. Please help!!

How to save data with association in gorm golang?

So, I want to save the movies and movie_genres data, but it always fails, which is stored in the database is the movies table as much as looping movie_genres, and the movie_genres column with the wrong movies ID. This is the result
movies table
movie_genres table
This the JSON result from frontend
{
"title":"Qui aut consectetur",
"release_date":"1974-11-25",
"runtime":"91",
"mpaa_rating":"PG",
"rating":"2",
"description":
"Anim dolor molestias",
"genre_id":["1","2"]
}
Below is my code on go
models
type Movie struct {
ID int `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Year int `json:"year"`
ReleaseDate time.Time `json:"release_date"`
Runtime int `json:"runtime"`
Rating int `json:"rating"`
MPAARating string `json:"mpaa_rating"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Genres []Genre `json:"genres" gorm:"many2many:movie_genres"`
MovieGenre []MovieGenre `json:"movie_genres" gorm:"many2many:movie_genres"`
}
type Genre struct {
ID int `json:"id"`
GenreName string `json:"name"`
Movies []Movie `json:"movies" gorm:"many2many:movie_genres"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
type MovieGenre struct {
ID int `json:"id"`
MovieID int `json:"movie_id"`
Movie Movie `gorm:"foreignKey:MovieID"`
GenreID int `json:"genre_id"`
Genre Genre `gorm:"foreignKey:GenreID"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
handler.go
func (app *Application) CreateMovies(ctx *gin.Context) {
var payload web.MoviePayloadResponse
if err := ctx.BindJSON(&payload); err != nil {
log.Println(err)
return
}
var movieGenre models.MovieGenre
movieGenre.Movie.ID, _ = strconv.Atoi(payload.ID)
movieGenre.Movie.Title = payload.Title
movieGenre.Movie.Description = payload.Description
movieGenre.Movie.ReleaseDate, _ = time.Parse("2006-01-02", payload.ReleaseDate)
movieGenre.Movie.Year = movieGenre.Movie.ReleaseDate.Year()
movieGenre.Movie.Runtime, _ = strconv.Atoi(payload.Runtime)
movieGenre.Movie.Rating, _ = strconv.Atoi(payload.Rating)
movieGenre.Movie.MPAARating = payload.MPAARating
movieGenre.Movie.CreatedAt = time.Now()
movieGenre.Movie.UpdatedAt = time.Now()
movieGenre.ID, _ = strconv.Atoi(payload.ID)
movieGenre.MovieID = movieGenre.Movie.ID
movieGenre.CreatedAt = time.Now()
movieGenre.UpdatedAt = time.Now()
err := app.models.Repository.CreateMovie(movieGenre.Movie)
if err != nil {
panic(err)
}
for _, v := range payload.GenreID {
movieGenre.GenreID, _ = strconv.Atoi(v)
err := app.models.Repository.CreateMovieGenres(movieGenre)
if err != nil {
panic(err)
}
}
ctx.JSON(http.StatusOK, &gin.H{
"ok": "response",
})
return
}
repository.go
func (MovieRepositoryImpl *MovieRepositoryImpl) CreateMovie(movie Movie) error {
MovieRepositoryImpl.DB.Create(&movie)
return nil
}
func (MovieRepositoryImpl *MovieRepositoryImpl) CreateMovieGenres(movieGenre MovieGenre) error {
MovieRepositoryImpl.DB.Create(&movieGenre)
return nil
}
payload
type MoviePayloadResponse struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Year string `json:"year"`
ReleaseDate string `json:"release_date"`
Runtime string `json:"runtime"`
Rating string `json:"rating"`
MPAARating string `json:"mpaa_rating"`
GenreID []string `json:"genre_id"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
The results that I expect are in the movies table, only 1 column is made, and in the movie_genres table store data movies as much as the genre inputted with the new movies ID. How to solve the problem?

Gorm Query Customized Join Extra Column

I am trying to get extra columns from a many2many relationships on Gorm. Example
Part
type Part struct {
Id unit
Name string
}
Diagram
type Diagram struct {
Id unit
Name string
Parts []Part `gorm:"many2many:diagram_parts;"`
}
DiagramPart
type DiagramPart struct{
DiagramId uint `gorm:"primaryKey"`
PartId uint `gorm:"primaryKey"`
PartDiagramNumber int
PartNumber string
PartDescription string
}
This is what I have done trying to retrieve PartNumber and PartDescription in Parts.
diagram := &Diagram{}
db := s.db.Where("id = ?", 1).
Preload("Parts", func(db *gorm.DB) *gorm.DB {
return db.Select("parts.*, diagram_parts.part_number, diagram_parts.part_description").
Joins("left join diagram_parts on diagram_parts.part_id = parts.id")
}).
First(diagram)
Unfortunately, I am not able to retrieve part_number, part_description. How should I go about it?
You can add field PartNumber and PartDescription on struct Part OR Diagram, then add tag gorm:"-:migration;->" on than fields to ignore migration and to readonly mode. But on your situation, you can add it in struct Part because you already preload it.
source: https://gorm.io/docs/models.html#Field-Level-Permission
here's the example:
package main
import (
"fmt"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Part struct {
Id uint `gorm:"primaryKey"`
Name string
PartNumber string `gorm:"-:migration;->"`
PartDescription string `gorm:"-:migration;->"`
}
type Diagram struct {
Id uint `gorm:"primaryKey"`
Name string
Parts []Part `gorm:"many2many:diagram_parts;"`
// PartNumber string `gorm:"-:migration;->"`
// PartDescription string `gorm:"-:migration;->"`
}
type DiagramPart struct {
DiagramId uint `gorm:"primaryKey"`
PartId uint `gorm:"primaryKey"`
PartDiagramNumber int
PartNumber string
PartDescription string
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&Diagram{}, &Part{}, &DiagramPart{})
diagram := &Diagram{}
err = db.Debug().Where("id = ?", 1).
// Select("diagrams.*, diagram_parts.part_number, diagram_parts.part_description").
Preload("Parts", func(db *gorm.DB) *gorm.DB {
return db.Select("parts.*, diagram_parts.part_number, diagram_parts.part_description").
Joins("left join diagram_parts on diagram_parts.part_id = parts.id")
}).
// Joins("left join diagram_parts on diagram_parts.diagram_id = diagrams.id").
First(diagram).Error
if err != nil {
panic(err)
}
fmt.Printf("diagram: %v\n", diagram)
fmt.Println("part number:", diagram.Parts[0].PartNumber)
}

Receiving inconsistent data in Go api

I was learning the Go language and tested Google Cloud Functions with go + Google Firestore as the database.
While I was testing the response I got inconsistent responses.
I have used the json Marshaller to convert Firebase data to Json object to return from the API, this API is hosted in the Google Cloud Functions.
// Package p contains an HTTP Cloud Function.
package p
import (
"context"
"fmt"
"log"
"net/http"
s "strings"
"encoding/json"
"cloud.google.com/go/firestore"
"google.golang.org/api/iterator"
)
func HelloWorld(w http.ResponseWriter, r *http.Request) {
path := s.Replace(r.URL.Path, "/", "", -1)
ctx := context.Background()
client := createClient(ctx)
iter := client.Collection("profile").Where("publicUrl", "==", path).Documents(ctx)
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
var publicDTO PublicDTO
var Profile Profile
doc.DataTo(&Profile)
publicDTO.Profile = Profile
b, err := json.Marshal(publicDTO)
if err != nil {
fmt.Println(err)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(b)
}
}
func createClient(ctx context.Context) *firestore.Client {
projectID := "projectId"
client, err := firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
return client
}
type PublicDTO struct {
Profile Profile `json:"profile"`
}
type Profile struct {
Id string `json:"id"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
FullName string `json:"fullName"`
Email string `json:"email"`
ImageUrl string `json:"imageUrl"`
CoverPic string `json:"coverPic"`
Experience int `json:"experience"`
PhoneNumber string `json:"phoneNumber"`
Description string `json:"description"`
Address string `json:"address"`
State string `json:"state"`
Country string `json:"country"`
Dob map[string]string `json:"dob"`
Website string `json:"website"`
Reputation int `json:"reputation"`
MemberFrom map[string]int `json:"memberFrom"`
Title string `json:"title"`
Organization string `json:"organization"`
Status string `json:"status"`
Setup int `json:"setup"`
Social map[string]string `json:"social"`
PublicUrl string `json:"publicUrl"`
Language []string `json:"language"`
Interests []string `json:"interests"`
}
but each time the response i'm getting is inconsistent, some of the values are missing.
The solution i got after marshal and unmarshal, it works as expected.
package p
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
s "strings"
"time"
"cloud.google.com/go/firestore"
"google.golang.org/api/iterator"
)
var ctx context.Context
var client *firestore.Client
func PublicApi(w http.ResponseWriter, r *http.Request) {
path := s.Replace(r.URL.Path, "/", "", -1)
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
newFsConfigBytes, _ := json.Marshal(getPublicDTO(path))
w.Write(newFsConfigBytes)
}
func getPublicDTO(path string) (publicDTO publicDTO) {
ctx = context.Background()
client = createClient()
profile, id := getProfiles(path)
publicDTO.Profile = profile
publicDTO.MilestoneDTOS = getMilestone(id)
return
}
func getProfiles(link string) (profile, string) {
var retVal profile
var id string
iter := client.Collection("profile").Where("publicUrl", "==", link).Documents(ctx)
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
id = doc.Ref.ID
b, _ := json.Marshal(doc.Data())
json.Unmarshal(b, &retVal)
}
return retVal, id
}
func getMilestone(id string) []milestoneDTOS {
var retVal []milestoneDTOS
iter := client.Collection("milestone").Where("userId", "==", id).Documents(ctx)
for {
var milestoneDTO milestoneDTOS
doc, err := iter.Next()
if err == iterator.Done {
break
}
b, _ := json.Marshal(doc.Data())
err = json.Unmarshal(b, &milestoneDTO)
if err != nil {
fmt.Println(err)
}
retVal = append(retVal, milestoneDTO)
}
return retVal
}
func createClient() *firestore.Client {
projectID := "app_id_asda"
client, err := firestore.NewClient(ctx, projectID)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
return client
}
type profile struct {
Address string `json:"address"`
City string `json:"city"`
Country string `json:"country"`
CoverPic string `json:"coverPic"`
CreatedBy string `json:"createdBy"`
CreatedDate int `json:"createdDate"`
Description string `json:"description"`
Dob int64 `json:"dob"`
Email string `json:"email"`
Enabled bool `json:"enabled"`
Experience int `json:"experience"`
FirstName string `json:"firstName"`
FullName string `json:"fullName"`
FullNameNoSpace string `json:"fullNameNoSpace"`
ImageURL string `json:"imageUrl"`
Interests []string `json:"interests"`
IsEnabled bool `json:"isEnabled"`
Language string `json:"language"`
LastModifiedDate int `json:"lastModifiedDate"`
LastName string `json:"lastName"`
LatLng string `json:"latLng"`
MemberFrom time.Time `json:"memberFrom"`
ObjectID string `json:"objectID"`
Organization string `json:"organization"`
PhoneNumber string `json:"phoneNumber"`
PlanID string `json:"planId"`
PublicURL string `json:"publicUrl"`
Reputation int `json:"reputation"`
Setup int `json:"setup"`
Social string `json:"social"`
State string `json:"state"`
Status string `json:"status"`
Title string `json:"title"`
Website string `json:"website"`
}
type milestoneDTOS struct {
Category string `json:"category"`
CreatedBy string `json:"createdBy"`
CreatedDate int `json:"createdDate"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
EndDate time.Time `json:"endDate"`
IsCurrentPosition bool `json:"isCurrentPosition"`
IsEnabled bool `json:"isEnabled"`
LastModifiedBy time.Time `json:"lastModifiedBy"`
LastModifiedDate int `json:"lastModifiedDate"`
ObjectID string `json:"objectID"`
Organization string `json:"organization"`
PictureURL string `json:"pictureURL"`
Profile string `json:"profile"`
Score float64 `json:"score"`
StartDate time.Time `json:"startDate"`
Tags []string `json:"tags"`
Title string `json:"title"`
URL string `json:"url"`
UserID string `json:"userId"`
}
type publicDTO struct {
Profile profile `json:"profile"`
MilestoneDTOS []milestoneDTOS `json:"milestoneDTOS"`
}

Many to many association with structs

I have this data structure here :
And I am having an issue linking the many-to-many association between Historique and Medicament. (History is all the time a patient went doctor, treatment are the treatment he received, medicament the medicament prescribed)
I have this code here and I can't find a way to link them with all these foreign keys !
type Traitement struct {
Histo_id int `gorm:"primary_key"`
Histo_patient_id int `gorm:"primary_key"`
Histo_medecin_id int `gorm:"primary_key"`
Medicament_id int `gorm:"primary_key"`
Debut_traitement string
Fin_traitement string
}
type Medicament struct {
ID int `gorm:"primary_key"`
Nom string `gorm:"column:medicament_nom"`
Description string `gorm:"column:medicament_desc"`
Historique []Historique `gorm:"many2many:tt_traitement"`
}
type Historique struct {
Fk_patient_id string `json:"-" gorm:"primary_key"`
Date_consultation string
Fk_maladie_id uint `json:"-" gorm:"primary_key"`
Fk_compte_medecin_id uint
Maladie Maladie `gorm:"ForeignKey:ID;AssociationForeignKey:Fk_maladie_id"`
Medicament []Medicament `gorm:"many2many:tt_traitement"`
}
func GetPatientWithDiseases(id uint) (*Patient, error) {
patient := &Patient{}
err := GetDB().Preload("Historique.Maladie").Preload("Historique.Traitement.Medicament").Find(&patient, id).Error
if err != nil {
return nil, err
}
return patient, nil
}
Thanks in advance for your help !
Ok, so after a lucky try, I had an error that led me to the good path.
I removed the Traitement struct, and the many_to_many and []Historique in the Medicament struct. I only kept:
type Historique struct {
ID int `gorm:"primary_key"`
Fk_patient_id string `json:"-" gorm:"primary_key"`
Date_consultation string
Fk_maladie_id uint `json:"-"`
Fk_compte_medecin_id uint `gorm:"primary_key"`
Maladie Maladie `gorm:"ForeignKey:ID;AssociationForeignKey:Fk_maladie_id"`
Medicament []Medicament `gorm:"many2many:tt_traitement"`
}
type Medicament struct {
ID int `gorm:"primary_key"`
Nom string `gorm:"column:medicament_nom"`
Description string `gorm:"column:medicament_desc"`
}
func GetPatientWithDiseases(id uint) (*Patient, error) {
patient := &Patient{}
err := GetDB().Preload("Historique.Maladie").Preload("Historique.Medicament").Find(&patient, id).Error
if err != nil {
return nil, err
}
return patient, nil
}
And things worked ! I just had to rename some of my columns, but as it is a dummy database, it wasn't an issue :) !
I hope this can help someone out there !

Resources