如何将表格数据写入Go中的嵌套结构体?

huangapple go评论82阅读模式
英文:

How to write table data into a nested struct in Go

问题

摘要

我正在尝试将几个postgres表中的数据写入一个嵌套的Go结构体,以便在我的Web应用程序中对GET请求返回单个JSON响应。

问题

  1. 从Go最佳实践的角度来看,我声明嵌套结构体的方式是否合理,还是应该避免这种方法,采用其他方式?
  2. 在第3步中,我做错了什么,导致我的代码无法工作?(我担心答案是“一切都错了”)

我已经完成的部分

  1. 我声明了我的结构体的结构
type MainObject struct {
	SubObjects []struct {
		SpecificDetail string `json:"specific-detail"`
	} `json:"sub-object"`
    // ...(其他结构体)...
}
  1. 我从表中检索了行
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行)...
  1. 我尝试(但失败了)将行数据构建到结构体中
	    for SubObjectDetail_rows.Next() {
		    SpecificDetail := NewMainObject.SubObject.SpecificDetail{}
	        SubObjectDetail_rows.Scan(&SpecificDetail)
		    SubObject = append(SubObject, SpecificDetail)
        }
        NewMainObject = append(MainObject, SubObject)
		defer persona_rows.Close()
  1. 最后,我设置了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

  1. 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?
  2. 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

  1. I've declared my struct of structs
type MainObject struct {

	SubObjects []struct {
		SpecificDetail string `json:"specific-detail"`
	                       }  `json:"sub-object"`

    ...(other []structs)...
}
  1. 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)...
  1. 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()
  1. 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 { /* ... */ }

huangapple
  • 本文由 发表于 2021年12月31日 20:37:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/70542415.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定