I want to join and preload 2 table and combine the result, but I could not get the desired result.
models.go
type Product struct {
ID uint `json:"-"`
Name string `json:"name"`
Description string `json:"description"`
}
type TransactionItem struct {
ID uint `json:"-"`
ProductID uint `json:"-"`
Qty int `json:"qty"`
Price int `json:"price"`
Product // I want to combine properties of Product into Transaction Item
}
controllers.go
var items []TransactionItem
if e := db.Preload("Product").Find(&items).Error; e != nil {
log.Println(e)
}
Desired result:
[
{
"qty": 1,
"price": 50,
"name": "Product name",
"description": "This is the product description"
}, { ... }
]
I have tried using "gorm:foreigKey=ProductID;references=ID;embedded;embeddedPrefix:product", and switching and trying out different combinations but still could not get the product.name and product.description to merge the data to TransactionItem. If I change Transaction Item to this:
type TransactionItem struct {
ID uint `json:"-"`
ProductID uint `json:"-"`
Qty int `json:"qty"`
Price int `json:"price"`
Product Product
}
//This will work and display data from product table, but the result is as follow:
[
{
"qty": 1,
"price": 50,
"product": {
"name": "Product name",
"description": "This is the product description"
}
}, { ... }
]
I can achieve the desired result by looping this result and manually set the name & description, but I think there should be a way for GORM to automatically do this, right? Thank you in advance.
To achieve your desired result where the Product fields are embedded directly within the TransactionItem in the resulting JSON, you have to use embedded structs and alias the embedded struct fields with the desired JSON field names.
Given the following structs, GORM automatically embeds the fields of the Product struct into TransactionItem:
type Product struct {
ID uint `json:"-"`
Name string `json:"name"`
Description string `json:"description"`
}
type TransactionItem struct {
ID uint `json:"-"`
ProductID uint `json:"-"`
Qty int `json:"qty"`
Price int `json:"price"`
Product `gorm:"foreignKey:ProductID"` // Embed Product struct
}
When GORM loads a TransactionItem, it should automatically load and embed the corresponding Product without the need to explicitly call Preload("Product").
However, this will generate the JSON structure like this:
{
"qty": 1,
"price": 50,
"ID": 1,
"Name": "Product name",
"Description": "This is the product description"
}
To generate your desired JSON structure, you would need to add JSON field tags to alias the fields of the embedded Product struct in the TransactionItem struct, like this:
type TransactionItem struct {
ID uint `json:"-"`
ProductID uint `json:"-"`
Qty int `json:"qty"`
Price int `json:"price"`
Name string `json:"name"` // Alias for Product.Name
Description string `json:"description"` // Alias for Product.Description
Product `gorm:"foreignKey:ProductID"` // Embed Product struct
}
This should generate your desired JSON structure:
{
"qty": 1,
"price": 50,
"name": "Product name",
"description": "This is the product description"
}
Remember to run this loading code without explicit preloading:
var items []TransactionItem
if e := db.Find(&items).Error; e != nil {
log.Println(e)
}
And note that this technique aliases the Product fields in TransactionItem, effectively overwriting them, so it's crucial to ensure there are no naming collisions between the fields in Product and TransactionItem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With