英文:
How to write table data into a nested struct in Go
问题
摘要
我正在尝试将几个postgres表中的数据写入一个嵌套的Go结构体,以便在我的Web应用程序中对GET请求返回单个JSON响应。
问题
- 从Go最佳实践的角度来看,我声明嵌套结构体的方式是否合理,还是应该避免这种方法,采用其他方式?
- 在第3步中,我做错了什么,导致我的代码无法工作?(我担心答案是“一切都错了”)
我已经完成的部分
- 我声明了我的结构体的结构
type MainObject struct {
SubObjects []struct {
SpecificDetail string `json:"specific-detail"`
} `json:"sub-object"`
// ...(其他结构体)...
}
- 我从表中检索了行
func getMainObjectHandler(w http.ResponseWriter, r *http.Request) {
// ...(数据库连接)...
MainObjectID := r.URL.Query().Get("moid")
if MainObjectID != "null" {
NewMainObject := MainObject{}
SubObjectDetail_rows, err := db.Query("SELECT specific_detail from the_table WHERE moid='" + MainObjectID + "'")
if err != nil {
log.Fatalf("could not execute query: %v", err)
}
// ...(其他db.Query行)...
- 我尝试(但失败了)将行数据构建到结构体中
for SubObjectDetail_rows.Next() {
SpecificDetail := NewMainObject.SubObject.SpecificDetail{}
SubObjectDetail_rows.Scan(&SpecificDetail)
SubObject = append(SubObject, SpecificDetail)
}
NewMainObject = append(MainObject, SubObject)
defer persona_rows.Close()
- 最后,我设置了Marshal和write
NMOListBytes, err := json.Marshal(NewMainObject)
if err != nil {
fmt.Println(fmt.Errorf("Error: %v", err))
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Write(NMOListBytes)
英文:
Summary
I am trying to write data from several postgres tables into a nested Go struct for the purpose of returning a single json response to a GET request within my web app.
Questions
- Is the way I'm declaring a nested struct reasonable from a Go best practices perspective, or is there a reason I should avoid this method and do it another way?
- What am I doing wrong in Step 3 to prevent my code from working? (I fear the answer is 'everything')
What I've got so far
- I've declared my struct of structs
type MainObject struct {
SubObjects []struct {
SpecificDetail string `json:"specific-detail"`
} `json:"sub-object"`
...(other []structs)...
}
- I've retrieved rows from the tables
func getMainObjectHandler(w http.ResponseWriter, r *http.Request) {
...(database connnection)...
MainObjectID := r.URL.Query().Get("moid")
if MainObjectID != "null" {
NewMainObject := MainObject{}
SubObjectDetail_rows, err := db.Query("SELECT specific_detail from the_table WHERE moid= '" + MainObjectID + "'")
if err != nil {
log.Fatalf("could not execute query: %v", err)
}
...(other db.Query rows)...
- I've tried (and failed) to build the row data into the struct.
for SubObjectDetail_rows.Next() {
SpecificDetail := NewMainObject.SubObject.SpecificDetail{}
SubObjectDetail_rows.Scan(&SpecificDetail)
SubObject = append(SubObject, SpecificDetail)
}
NewMainObject = append(MainObject, SubObject)
defer persona_rows.Close()
- Finally, I've set up Marshal and write.
NMOListBytes, err := json.Marshal(NewMainObject)
if err != nil {
fmt.Println(fmt.Errorf("Error: %v", err))
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Write(NMOListBytes)
答案1
得分: 1
首先,在创建 SQL 查询时,请使用占位符来避免注入攻击:
// db.Query("SELECT specific_detail from the_table WHERE moid= '" + MainObjectID + "'") // 不要这样写
db.Query("SELECT specific_detail from the_table WHERE moid=?", MainObjectID)
除非你使用像 GORM
这样的框架,否则无法将结果 Scan()
到单个结构体值中。
根据文档:
Scan 将当前行的列复制到 dest 指向的值中。dest 中的值的数量必须与 Rows 中的列数相同。
看起来你正在从数据库查询中获取 JSON 数据,因为你只查询了一列,所以你可能想要:
var bs []byte // 获取原始的 JSON 字节
err = SubObjectDetail_rows.Scan(&bs)
if err != nil { /* 总是检查错误 */ }
然后将其解组为你的结构体:
```go
err = json.Unmarshal(bs, &SpecificDetail)
if err != nil { /* ... */ }
英文:
Firstly, please use placeholders when creating your SQL query to avoid injections:
// db.Query("SELECT specific_detail from the_table WHERE moid= '" + MainObjectID + "'") // not this
db.Query("SELECT specific_detail from the_table WHERE moid=?", MainObjectID)
Unless you're using a framework like GORM
you can't Scan()
into a single struct value.
From the docs:
> Scan copies the columns in the current row into the values pointed at
> by dest. The number of values in dest must be the same as the number
> of columns in Rows.
It looks like you're pulling JSON from a DB query, as you're only querying one column, so you probably want:
var bs []byte // get raw JSON bytes
err = SubObjectDetail_rows.Scan(&bs)
if err != nil { /* always check errors */ }
and then unmarshal them to your struct:
err = json.Unmarshal(bs, &SpecificDetail)
if err != nil { /* ... */ }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论