I have a struct definition in GO like this
package models
//StoryStatus indicates the current state of the story
type StoryStatus string
const (
//Progress indicates a story is currenty being written
Progress StoryStatus = "progress"
//Completed indicates a story was completed
Completed StoryStatus = "completed"
)
//Story holds detials of story
type Story struct {
ID int
Title string `gorm:"type:varchar(100);unique_index"`
Status StoryStatus `sql:"type ENUM('progress', 'completed');default:'progress'"`
Paragraphs []Paragraph `gorm:"ForeignKey:StoryID"`
}
//Paragraph is linked to a story
//A story can have around configurable paragraph
type Paragraph struct {
ID int
StoryID int
Sentences []Sentence `gorm:"ForeignKey:ParagraphID"`
}
//Sentence are linked to paragraph
//A paragraph can have around configurable paragraphs
type Sentence struct {
ID uint
Value string
Status bool
ParagraphID uint
}
I am using GORM for orm in GO.
How do I fetch all the information for a story based on story id like all the paragraphs and all the sentences for each paragraph.
The GORM example show only with 2 models to use preload
This is what you're looking for:
db, err := gorm.Open("mysql", "user:password#/dbname?charset=utf8&parseTime=True&loc=Local")
defer db.Close()
story := &Story{}
db.Preload("Paragraphs").Preload("Paragraphs.Sentences").First(story, 1)
It finds the story with the id = 1 and preloads its relationships
fmt.Printf("%+v\n", story)
This prints out the result nicely for you
Side note:
You can turn on log mode of Gorm so that you can see the underlying queries, to debug, or any other purposes:
db.LogMode(true)
Looking this [example][1] this One to many.
package main
import (
"log"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/kylelemons/godebug/pretty"
)
// Order
type Order struct {
gorm.Model
Status string
OrderItems []OrderItem
}
// Order line item
type OrderItem struct {
gorm.Model
OrderID uint
ItemID uint
Item Item
Quantity int
}
// Product
type Item struct {
gorm.Model
ItemName string
Amount float32
}
var (
items = []Item{
{ItemName: "Go Mug", Amount: 12.49},
{ItemName: "Go Keychain", Amount: 6.95},
{ItemName: "Go Tshirt", Amount: 17.99},
}
)
func main() {
db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
db.LogMode(true)
if err != nil {
log.Panic(err)
}
defer db.Close()
// Migrate the schema
db.AutoMigrate(&OrderItem{}, &Order{}, &Item{})
// Create Items
for index := range items {
db.Create(&items[index])
}
order := Order{Status: "pending"}
db.Create(&order)
item1 := OrderItem{OrderID: order.ID, ItemID: items[0].ID, Quantity: 1}
item2 := OrderItem{OrderID: order.ID, ItemID: items[1].ID, Quantity: 4}
db.Create(&item1)
db.Create(&item2)
// Query with joins
rows, err := db.Table("orders").Where("orders.id = ? and status = ?", order.ID, "pending").
Joins("Join order_items on order_items.order_id = orders.id").
Joins("Join items on items.id = order_items.id").
Select("orders.id, orders.status, order_items.order_id, order_items.item_id, order_items.quantity" +
", items.item_name, items.amount").Rows()
if err != nil {
log.Panic(err)
}
defer rows.Close()
// Values to load into
newOrder := &Order{}
newOrder.OrderItems = make([]OrderItem, 0)
for rows.Next() {
orderItem := OrderItem{}
item := Item{}
err = rows.Scan(&newOrder.ID, &newOrder.Status, &orderItem.OrderID, &orderItem.ItemID, &orderItem.Quantity, &item.ItemName, &item.Amount)
if err != nil {
log.Panic(err)
}
orderItem.Item = item
newOrder.OrderItems = append(newOrder.OrderItems, orderItem)
}
log.Print(pretty.Sprint(newOrder))
}
[1]: https://stackoverflow.com/questions/35821810/golang-gorm-one-to-many-with-has-one
Related
People, I am trying to save an employee in the employee table, it already saves and everything is fine, the problem is when I try to save the schedule that is related to another table where schedule_id is the foreign of the employee table and is related to the id of the time table, this is the code:
Controlador
func Save(writer http.ResponseWriter, request *http.Request) {
employe := models.Employe{}
db := common.GetConnection()
error := json.NewDecoder(request.Body).Decode(&employe)
if error != nil {
log.Fatal(error)
common.SendError(writer, http.StatusBadRequest)
return
}
randomBytes := make([]byte, 2)
_, err := rand.Read(randomBytes)
if err != nil {
log.Fatal(error)
common.SendError(writer, http.StatusBadRequest)
return
}
employe.PinEmploye = hex.EncodeToString(randomBytes)
horary := models.Employe{Arrival: employe.Arrival, Departure: employe.Departure}
error = db.Save(&horary).Error
if error != nil {
log.Fatal(error)
common.SendError(writer, http.StatusInternalServerError)
return
}
employe.ScheduleId = horary.ID
error = db.Save(&employe).Error
if error != nil {
log.Fatal(error)
common.SendError(writer, http.StatusInternalServerError)
return
}
json, _ := json.Marshal(employe)
common.SendResponse(writer, http.StatusCreated, json)
fmt.Println(employe)
}
structs
type Employe struct {
ID int `json:"id" gorm:"primary_key;auto_increment"`
PinEmploye string `json:"pinEmploye" gorm:"FOREIGNKEY:PinEmploye" `
FirstName string `json:"first_name" `
LastName string `json:"last_name"`
Company string `json:"company"`
Position string `json:"position"`
ScheduleId int `json:"schedule_id"`
// Arrival time.Time `json:"arrival"`
// Departure time.Time `json:"departure"`
CreatedAt time.Time `json:"fechacreacion"`
}
Horary:
type Horary struct {
ID int `json:"id" gorm:"primary_key;auto_increment"`
Arrival time.Time `json:"arrival"`
Departure time.Time `json:"departure"`
}
I tried to do it with entities but I still don't know very well about the subject
type Employe struct {
ID int `json:"id" gorm:"primary_key;auto_increment"`
PinEmploye string `json:"pinEmploye" gorm:"FOREIGNKEY:PinEmploye" `
FirstName string `json:"first_name" `
LastName string `json:"last_name"`
Company string `json:"company"`
Position string `json:"position"`
ScheduleId int `json:"schedule_id"`
CreatedAt time.Time `json:"fechacreacion"`
}
I have tried with entity model but still can't do it, I tried to do it with chatGPT but still can't
I have a simple SELECT statement which calls all of the columns in my coupon table by who_added.
code:
func CouponByUserID(c *gin.Context) {
fmt.Println("CouponByUserID()")
lCoupon := []model.Coupon{}
whoAdded := c.PostForm("whoAdded")
fmt.Println("whoAdded: " + whoAdded)
var sqlSel = ""
sqlSel = sqlSel + " SELECT * FROM coupon WHERE who_added = ? "
fmt.Println("sqlSel")
fmt.Println(sqlSel)
_, err := dbmap.Select(&lCoupon, sqlSel, whoAdded)
if err == nil || lCoupon != nil {
fmt.Println("got result")
fmt.Println(lCoupon)
c.Header("Content-Type", "application/json")
c.JSON(http.StatusOK, lCoupon)
} else {
fmt.Println("coupon not found")
c.JSON(404, gin.H{"error": "coupon not found"})
}
}
Coupon Model:
type Coupon struct {
CouponID int64 `db:"coupon_id, primarykey, autoincrement"`
CouponName string `db:"coupon_name,omitempty"`
CouponCode string `db:"coupon_code,omitempty"`
Description string `db:"description,omitempty"`
Status string `db:"status,omitempty"`
CampaignStart int64 `db:"campaign_start,omitempty"`
CampaignEnd int64 `db:"campaign_end,omitempty"`
SourceType string `db:"source_type,omitempty"`
Preview string `db:"preview,omitempty"`
CouponFormat string `db:"coupon_format,omitempty"`
PreviewType string `db:"preview_format,omitempty"`
Display string `db:"display,omitempty"`
DisplayType string `db:"display_format,omitempty"`
Width float64 `db:"width,omitempty"`
Height float64 `db:"height,omitempty"`
WhoAdded int `db:"who_added,omitempty"`
WhenAdded int `db:"when_added,omitempty"`
WhoUpdated int `db:"who_updated,omitempty"`
WhenUpdated int `db:"when_updated,omitempty"`
TermsAndCondition string `db:"terms_and_condition,omitempty"`
CouponLocation string `db:"coupon_location,omitempty"`
BusID string `db:"bus_id,omitempty"`
ImgCoupon string `db:"img_coupon,omitempty"`
}
Result:
As you can see here it's empty even if my table has data.
Problem: Data on my table is not showing in the result.
I tried to query the same statement on MySQL workbench and it's work just fine.
Where did I go wrong?
Having a bit of a head scratcher moment. I've got the following struct:
type Room struct {
ID int
Name string
RoomType int
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
GroupId int
BlockId int
ProjectId int
RoomLength float64
RoomWidth float64
CeilingHeight float64
CeilingColorHex string
WallColorHex string
FloorColorHex string
CeilingColorRgb string
WallColorRgb string
FloorColorRgb string
}
Reading it out in rest api with:
database := db.New()
stmt, err := database.Prepare("SELECT * FROM room WHERE block_id = ?")
if err != nil {
panic(err)
}
defer stmt.Close()
rows, err := stmt.Query(c.Param("id"))
if err != nil {
panic(err)
}
defer rows.Close()
var rooms []common.Room
for rows.Next() {
var r common.Room
err := rows.Scan(&r.ID, &r.Name, &r.RoomType, &r.CreatedAt, &r.UpdatedAt, &r.DeletedAt,
&r.GroupId, &r.BlockId, &r.ProjectId, &r.RoomLength, &r.RoomWidth, &r.CeilingHeight,
&r.CeilingColorHex, &r.WallColorHex, &r.FloorColorHex, &r.CeilingColorRgb, &r.WallColorRgb,
&r.FloorColorRgb)
if err = rows.Err(); err != nil {
panic(err)
}
fmt.Printf("Found: %v", r)
rooms = append(rooms, r)
}
Yet, the resulting payload is:
{3 Loki #1 3 2018-09-25 08:42:38 +0000 UTC 2018-09-25 14:52:39 +0000 UTC 0001-01-01 00:00:00 +0000 UTC 0 0 0 0 0 0 }
I'm specifically after the length/width, which (above) are 0. Yet in the db:
mysql> select * from room where id = 3 \G
*************************** 1. row ***************************
id: 3
name: Loki #1
room_type: 3
created_at: 2018-09-25 08:42:38
updated_at: 2018-09-25 14:52:39
deleted_at: NULL
group_id: 0
block_id: 1
project_id: 0
room_length: 10
room_width: 7
ceiling_height: 4
ceiling_color_hex: #c0c0c0
wall_color_hex: #a9a9a9
floor_color_hex: #708090
ceiling_color_rgb: 192,192,192
wall_color_rgb: 169,169,169
floor_color_rgb: 112,128,144
1 row in set (0.00 sec)
I thought it may have something to do with differing types, but after changing them in the db, and then in code, no change. Can anyone explain why .Scan isn't picking up certain values?
Thanks!
First of all, check the error which come from rows.Scan(). You only check the error from rows.Err() which is a different kind of error, and not related to the scan.
err := rows.Scan(&r.ID, &r.Name, &r.RoomType, &r.CreatedAt, &r.UpdatedAt, &r.DeletedAt,
&r.GroupId, &r.BlockId, &r.ProjectId, &r.RoomLength, &r.RoomWidth, &r.CeilingHeight,
&r.CeilingColorHex, &r.WallColorHex, &r.FloorColorHex, &r.CeilingColorRgb, &r.WallColorRgb,
&r.FloorColorRgb)
if err != nil {
panic(err) // Error related to the scan
}
if err = rows.Err(); err != nil {
panic(err) // Error related to the iteration of rows
}
When the value from deleted_at is return as NULL, Scan will return an error such as unsupported Scan, storing driver.Value type <nil> into type *time.Time and the rest of your struct will get zero values.
It means that your room struct has to change to use a pointer to time.
CreatedAt *time.Time
UpdatedAt *time.Time
DeletedAt *time.Time
However, you may need to add into you sql.Open() the parameter parseTime sql.Open("mysql", "user:password#/dbname?parseTime=true) to parse the time correctly for mysql.
You should then received a valid *time.Time when it is set, or nil when it is NULL.
I have a mysql query, struct and code like that:
sqlQuery := "SELECT group_concat(Id), Title from Tbl WHERE SomeField = 3 GROUP BY Title ORDER BY Title LIMIT 20;"
type SomeStruct struct {
IDs []int `json:"ids"`
Title string `json:"title"`
SomeField int `json:"somefield"`
}
type SomeMap map[string]interface{}
var SomeObject []SomeMap
row, err := db.Query(sqlQuery)
checkErr(err)
for row.Next() {
var ids []int
var title string
var somefield int
err = row.Scan(&ids, &title, &somefield)
someMap := SomeMap{"ids":ids, "title": title, "somefield": somefield}
someObject = append(SomeObject, someMap)
}
How can I unmashal my object to struct where IDs look like []int type because golang tells that it might be []uint8 ??
I have a struct called Ads
type Ads struct {
ID int `json:"id"`
Subject string `json:"subject"`
Phone string `json:"phone"`
}
func GetAdsPostgres() (ads []Ads, err error) {
ads = make([]Ads, 0)
rows, err := db1.Query("Select ad_id, subject FROM ads limit 200 ")
for rows.Next() {
var ad Ads
rows.Scan(&ad.ID, &ad.Subject)
test := reflect.ValueOf(ad.ID)
addd := test.Interface().(int)
rows1, _ := db1.Query("Select phone FROM ads where ad_id=$1", addd)
rows1.Scan(&ad.Phone)
ads = append(ads, ad)
rows1.Close()
}
if err = rows.Err(); err != nil {
return
}
return
}
without thinking of join the table because the phone has multipte enumeration values which I have to reform them as fields after
Just get the phone number too in the first query; don't repeat yourself.
db1.Query("Select ad_id, subject, phone FROM ads limit 200 ")