I have the following JSON document:
{
id: int
transaction_id: string
total: string
line_items: [
{
id: int
name: string
}
]
}
This is my code
type Order struct {
ID int `json:"id"`
TransactionId string `json:"transaction_id"`
Total string `json:"total"`
LineItems []interface{} `json:"line_items"`
}
...
var order Order
json.Unmarshal([]byte(sbody), &order)
for index, a := range order.LineItems {
fmt.Println(a["name"])
}
I got the error:
invalid operation: cannot index a (variable of type interface{})
Should I create an Item struct?
Modify the LineItems field type to []map[string]interface{}.
package main
import (
"encoding/json"
"fmt"
)
func main() {
type Order struct {
ID int `json:"id"`
TransactionId string `json:"transaction_id"`
Total string `json:"total"`
LineItems []map[string]interface{} `json:"line_items"`
}
var order Order
err := json.Unmarshal([]byte(`{
"id": 1,
"transaction_id": "2",
"total": "3",
"line_items": [
{
"id": 2,
"name": "444"
}
]
}`), &order)
if err != nil {
panic(err)
}
for _, a := range order.LineItems {
fmt.Println(a["name"])
}
}
In relation store has many products.
I created the struct like this:
type Store1 struct {
StoreSeq uint `json:"storeSeq" gorm:"primaryKey; column:store_seq"`
NickName string `json:"nickName" gorm:"column:nick_name"`
RegDate *domain.CTime `json:"regDate" gorm:"column:reg_date"`
Product1 []Product1 `json:"products" gorm:"foreignKey:ProductSeq"`
}
func (*Store1) TableName() string {
return "store"
}
type Product1 struct {
ProductSeq uint `json:"productSeq"`
ProductTitle string `json:"productTitle"`
RegDate *domain.CTime `json:"regDate"`
StoreSeq *uint `json:"store_seq" `
}
func (*Product1) TableName() string {
return "product"
}
and I queried it like this:
pro := new(entity.Product1)
store := new(entity.Store1)
orm.GetData().
Model(pro).
Preload("Product1").
Joins("left join store on store.store_seq = product.store_seq").
Where("store.store_seq = ?", 1).
Find(&store)
In my database table has data like this
STORE
1 testStore 2022-03-01 23:19:18
PRODUCT
1 1 test 2022-03-01 23:19:18
2 1 testaaa 2022-03-01 23:19:18
I expect
"storeSeq": 1,
"nickName": "",
"regDate": "2022-03-01 23:19:18",
"products": [
{
"productSeq": 1,
"productTitle": "test",
"regDate": "2022-03-01 23:19:18",
"store_seq": 1
},
{
"productSeq": 2,
"productTitle": "testaaa",
"regDate": "2022-03-01 23:19:18",
"store_seq": 1
}
]
but it only returns one result:
"storeSeq": 1,
"nickName": "",
"regDate": "2022-03-01 23:19:18",
"products": [
{
"productSeq": 1,
"productTitle": "test",
"regDate": "2022-03-01 23:19:18",
"store_seq": 1
}
]
I checked the SQL query then I found that it executes two SQL queries
[1.725ms] [rows:2] SELECT `product`.`product_seq`,`product`.`product_title`,`product`.`reg_date`,`product`.`store_seq` FROM `product` WHERE `product`.`product_seq` = 1
AND
[6.370ms] [rows:1] SELECT `product`.`product_seq`,`product`.`product_title`,`product`.`reg_date`,`product`.`store_seq` FROM `product` left join store on store.store_seq = product.store_seq WHERE store.store_seq = 1
I don't know why it executes the first SQL query; I want it to execute the second query only.
I have no idea and this is my firstime to use Golang with gorm with serverless framework
I found out that I make wrong releation between product and store
store has many produts so I have to relation product1 []Product1 foriegnKey
with storeSeq but i set foriegnkey as product_seq
and i also find out that execute two queries it because of preload option.
Hi let's say that I have 3 Structs in the following format
type Employee struct {
Id int
Name string
CompanyId int `gorm:"column:companyId"`
Company Company `gorm:"foreignKey:CompanyId"`
}
type Company struct {
Id int
CompanyName string
OwnerId `gorm:"column:owner"`
Owner Owner `gorm:"foreignKey:OwnerId"`
}
type Owner struct {
Id int
Name string
Age int
Email string
}
func (E Employee) GetAllEmployees() ([]Employee, error) {
Employees := []Employee
db.Preload("Company").Find(&Employees)
}
// -- -- There response will be like
[
{
id: 1
name: "codernadir"
company: {
id: 5
company_name: "Company"
owner: {
id 0
Name ""
Age 0
Email ""
}
}
}
]
here I'm getting Owner values with the default values.
the given examples are for describing what I'm trying to reach.
I need a way how to load the Owner struct with its values when I load the Employees?
any suggestions will be appreciated and thanks in advance
You can use the gorm:"embedded" tag:
type Employee struct {
Id int
Name string
CompanyId int `gorm:"column:companyId"`
Company Company `gorm:"embedded"`
}
type Company struct {
Id int
CompanyName string
OwnerId `gorm:"column:owner"`
Owner Owner `gorm:"embedded"`
}
type Owner struct {
Id int
Name string
Age int
Email string
}
this is what I found as a solution to load the nested objects from embedded structs
db.Preload("Company").Preload("Company.Owner").Find(&Employees)
I am new to Go, is there any one who knows how to query the int64 filed with between and in Go/gorm?
I would like to use below sql select * from porject where created_at between ? and ?;, but I don't know how to do it? thanks so much for any advice.
type Project struct {
Id int64 `json:"id" gorm:"primary_key;AUTO_INCREMENT;comment:'id'"`
Email string `json:"email" gorm:"type:varchar(255);comment:'email'"`
CreatedAt int64 `json:"created_at" gorm:"type:bigint(20);comment:'created_time'"`
}
func (p *Project) ProjectList(pageInfo cts.PageInfo) ([]Project, int, error) {
if p.Email != "" {
db = db.Where("email like ?", "%"+p.Email+"%")
}
if p.CreatedAt != 0 {
db = db.Where("created_at <> ?", p.CreatedAt)
}
err1 := db.Offset((pageInfo.Page - 1) * pageInfo.PageSize).Limit(pageInfo.PageSize).Order("id desc").Find(&List).Error
db.Count(&total)
return List, total, err1
}
I need to pass front end to query data by below json
{
"page": 1,
"page_size": 20,
"email":"test#test",
"create_at_st": 1654176767,
"create_at_end": 1654896767
}
or
{
"page": 1,
"page_size": 20,
"email":"test#test",
"create_at": ['1654176767','1654896767']
}
or other json, as long as it can achieve the desired effect.
I have modified your query ,assuming you have s.CreatedAtMin and s.CreatedAtMax with you .Then you can have something like
db.Where("created_at between ? and ?", min, max)
func (p *Project) ProjectList(pageInfo cts.PageInfo) ([]Project, int, error) {
if p.Email != "" {
db = db.Where("email like ?", "%"+s.Email+"%")
}
if p.CreatedAt != 0 {
//db = db.Where("created_at <> ?", s.CreatedAt)
db.Where("created_at between ? and ?", s.CreatedAtMin, s.CreatedAtMax)
}
err1 := db.Offset((pageInfo.Page - 1) * pageInfo.PageSize).Limit(pageInfo.PageSize).Order("id desc").Find(&List).Error
db.Count(&total)
return List, total, err1
}
I have json data like this:
json: {"opt1":200,"opt3":"1","opt4":"13","opt5":null,"products":[{"product_id":1,"price":100,"variant_id":100},{"product_id":1,"price":100,"variant_id":null}]}
I have structured it using
type Products struct {
Product_id int
Price json.Number
Variant_id int
}
type Pdata struct {
Products []Products `json:"products"`
}
Then I use unmarshal
jsonb := []byte(jsonVal)
var data Pdata
err := json.Unmarshal(jsonb, &data)
if err != nil {
fmt.Println(err)
return
}
And get output like
{[{1 100 100} {2 100 0}]}
Now I need to convert that data into a json object like this
{"purchased_products": [{"product_id": 1,"price": 1200,"variation_id": 100},{"product_id": 2,"price": 100,"variation_id": null}]}
After that, I need to assign it to "json"
var d = map[string]string{
"json": jsonVal,
"created_at": time.Now().Format("2006-01-02 15:04:05"),
"updated_at": time.Now().Format("2006-01-02 15:04:05"),
}
How can I do it?
Create a type (eg : PurchasedProducts) as below.
type PurchasedProducts struct {
Products []Products `json:"purchased_products"`
}
And init a PurchasedProducts type variable and assign your unmarshaled products to Purchased products as below.
pProducts := PurchasedProducts{Products: data.Products}
jsonByte, err := json.Marshal(pProducts)
if err != nil {
fmt.Println(err)
return
}
And convert that []byte array to a string and assign it to the map like below.
var d = map[string]string{
"json": string(jsonByte),
"created_at": time.Now().Format("2006-01-02 15:04:05"),
"updated_at": time.Now().Format("2006-01-02 15:04:05"),
}
You can run and see full code here.
Simply define two more structs that model the second JSON object:
type Pdata2 struct {
PurchasedProducts []Product2
}
type Product2 struct {
Product_id int
Price json.Number
Variation_id *int // pointer to int
}
The Variation_id field is an *int type because your required output JSON shows "variation_id": null. If you declare the field as simple int, its zero value will be marshaled to 0.
Then initialize those structs using values from the previous ones:
func main() {
data2 := Pdata2{
PurchasedProducts: make([]Product2, len(data.Products)),
}
for i, p := range data.Products {
data2.PurchasedProducts[i] = Product2{
Product_id: p.Product_id,
Price: p.Price,
Variation_id: nullableInt(p.Variant_id),
}
}
b, err := json.Marshal(data2)
if err != nil {
// ... handle error
}
var d = map[string]string{
"json": string(b),
// ...
}
fmt.Println(d)
}
func nullableInt(n int) *int {
if n == 0 {
return nil
}
return &n
}
Playground: https://play.golang.org/p/xhsmHNBjRKN
For nullable fields you can use pointers, so for example if the variant_id json field can be an integer or a json null, and you want to retain that information, then you can change Variant_id int to Variant_id *int.
type Product struct {
Product_id int `json:"product_id"`
Price json.Number `json:"price"`
Variant_id *int `json:"variant_id"`
}
To change json field names between unmarshal and marshal you can declare a second Products struct with the same fields as the original but with struct tags defining the desired field names, then, if the structs are, in all other respects, equivalent you can convert between them.
type Product struct {
Product_id int `json:"product_id"`
Price json.Number `json:"price"`
Variant_id int `json:"variant_id"`
}
type PurchasedProduct struct {
Product_id int `json:"product_id"`
Price json.Number `json:"price"`
Variant_id int `json:"variation_id"` // here variant_id becomes variation_id
}
Then, if p is of type Product, you can simply convert it to PurchasedProduct like so:
pp := PurchasedProduct(p)
To offload the conversion to the marshaling process you can have the original types implement the json.Marshaler interface and do the conversion there.
func (p Product) MarshalJSON() ([]byte, error) {
type P struct {
Product_id int `json:"product_id"`
Price json.Number `json:"price"`
Variant_id *int `json:"variation_id"`
}
return json.Marshal(P(p))
}
With the above you can do the following:
func main() {
// unmarshal
var pd Pdata
err := json.Unmarshal(data, &pd)
if err != nil {
panic(err)
}
// marshal
out, err := json.MarshalIndent(pd, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
https://play.golang.org/p/0gnrjgUslza
Here you are.
Assumptions are that:
Product is a model which could be much more complicated, thus it has dedicated structs. Thus transformation from Product to OutputProduct can be unit tested separately.
It is one time use application, not a part of the application which exposes an API. Otherwise it should be properly separated into layers and the output should be written as a structure.
package main
import (
"encoding/json"
"log"
"os"
"time"
)
type (
Product struct {
ProductID int `json:"product_id"`
VariantID int `json:"variant_id"`
Price json.Number
}
Products []Product
OutputProduct struct {
ProductID int `json:"product_id"`
VariantID int `json:"variation_id"`
Price json.Number
}
)
func (p Product) ToOutputProduct() OutputProduct {
return OutputProduct{
ProductID: p.ProductID,
VariantID: p.VariantID,
Price: p.Price,
}
}
func (p Products) ToOutputProducts() []OutputProduct {
outputProducts := make([]OutputProduct, len(p))
for i := 0; i < len(p); i++ {
outputProducts[i] = p[i].ToOutputProduct()
}
return outputProducts
}
func main() {
var inputJSON = `{"opt1":200,"opt3":"1","opt4":"13","opt5":null,"products":[{"product_id":1,"price":100,"variant_id":100},{"product_id":1,"price":100,"variant_id":null}]}`
var parsedInput struct {
Products Products
}
if err := json.Unmarshal([]byte(inputJSON), &parsedInput); err != nil {
log.Fatal(err)
}
var output = map[string]interface{}{
"json": map[string][]OutputProduct{
"purchased_products": parsedInput.Products.ToOutputProducts(),
},
"created_at": time.Now().Format("2006-01-02 15:04:05"),
"updated_at": time.Now().Format("2006-01-02 15:04:05"),
}
encoder := json.NewEncoder(os.Stdout)
encoder.SetIndent(" ", " ")
if err := encoder.Encode(output); err != nil {
log.Fatal(err)
}
}
Based on the suggestions from comments:
package main
import (
"encoding/json"
"log"
"time"
)
type Products struct {
Product_id int `json:"product_id"`
Price int `json:"price"`
Variant_id int `json:"variant_id"`
}
type ProductData struct {
Products []Products `json:"products"`
}
type Response struct {
Json json.RawMessage `json:"json"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
func main() {
productJson := `{
"opt1": 200,
"opt3": "1",
"opt4": "13",
"opt5": null,
"products": [
{ "product_id": 1, "price": 100, "variant_id": 100 },
{ "product_id": 1, "price": 100, "variant_id": null }
]
}`
productData := &ProductData{}
err := json.Unmarshal([]byte(productJson), &productData)
if err != nil {
panic(err)
}
b, err := json.Marshal(map[string]interface{}{"purchased_products": productData.Products})
if err != nil {
panic(err)
}
d := &Response{
Json: b,
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
UpdatedAt: time.Now().Format("2006-01-02 15:04:05"),
}
out, err := json.Marshal(d)
if err != nil {
panic(err)
}
log.Println(string(out))
}
Output:
2009/11/10 23:00:00 {"json":{"purchased_products":[{"product_id":1,"price":100,"variant_id":100},{"product_id":1,"price":100,"variant_id":0}]},"created_at":"2009-11-10 23:00:00","updated_at":"2009-11-10 23:00:00"}