Golang如何将列表整体而非逐行序列化为正确JSON格式?

Golang如何将列表整体而非逐行序列化为正确JSON格式? 我有这段代码可以将单行数据正确序列化输出:

var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()
colnames, _ := rows.Columns()
vals := make([]interface{}, len(cols))

for i, _ := range cols {  //bytes to string
   vals[i] = &cols[i]
}

mymap := make(map[string]interface{})

for i, v := range vals {  //adding column names
  mymap[colnames[i]] = v
}

for rows.Next() {
   err = rows.Scan(vals...)
   json, _ := json.Marshal(mymap)
   fmt.Fprintf(w,"%s\n",json)
}

输出结果会是这样的:

{“ID”:“1”,“NAME”:“John Doe”}
{“ID”:“2”,“NAME”:“Jane Doe”}

但我需要的是用逗号分隔的完整数据块:

[{“ID”:“1”,“NAME”:“John Doe”},
{“ID”:“2”,“NAME”:“Jane Doe”}]

作为一个完全的新手,我想应该序列化整个列表而不是每一行数据:

for rows.Next() {
   err = rows.Scan(vals...)
   append (list, vals)  //save to a list
}

json, _ := json.Marshal(list) //marshal the list instead of each row
fmt.Fprintf(w,"%s\n",json)

我该怎么做?


更多关于Golang如何将列表整体而非逐行序列化为正确JSON格式?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

11 回复

谢谢!作为新手我很好奇。这种列迭代方式会不会导致延迟?与你之前的解决方案相比如何?

更多关于Golang如何将列表整体而非逐行序列化为正确JSON格式?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我从StackOverflow找到了解决方案

只需创建一个切片来存储你的映射,然后进行序列化。

var mySlice = make([]map[string]interface{}, 0)
for rows.Next() {
err = rows.Scan(vals…)
mySlice = append(mySlice, mymap)
}
json, _ := json.Marshal(mySlice)
fmt.Printf("%s\n", json)

你在对切片值的指针进行复杂操作,并且总是扫描到同一个切片(vals,包含指向cols的指针)中,覆盖了原有值。我理解你试图基于表结构实现完全动态的功能,但初始代码中多层间接引用甚至让我都有些困惑。

func main() {
    fmt.Println("hello world")
}

calmh:

我理解你试图基于表结构实现完全动态的功能,但初始代码中的间接层级甚至让我都感到有些皱眉。

我完全是Golang的新手,正在通过实践学习。

主要目标是在不了解结构体的情况下从SQL获取数据,并将其解析为JSON。我开始觉得这对于新手来说要么不可能,要么太难了。

我认为这个版本更容易理解

var arr []string
for rows.Next() {
    err = rows.Scan(vals...)
    m := make(map[string]interface{})
    for i, v := range vals {
        m[colnames[i]] = v
    }
    str, _ := json.Marshal(m)
    arr = append(arr, string(str))
}

json, _ := json.Marshal(arr)
fmt.Println(string(json))
var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()
colnames, _ := rows.Columns()
vals := make([]interface{}, len(cols))

var arr []map[string]interface{}
for rows.Next() {
  err = rows.Scan(vals...)
  m := make(map[string]interface{})
  for i, v := range vals {
    m[colnames[i]] = v
  }
str, _ := json.Marshal(m)
fmt.Println(string(str))
arr = append(arr, m)
}

返回的结果只有一个"null"。请问我哪里做错了?

var mySlice = make([]map[string]interface{}, 0)
for rows.Next() {
   err = rows.Scan(vals…)
   mySlice = append(mySlice, mymap)
}

json, _ := json.Marshal(mySlice)
fmt.Printf("%s\n", json)

这输出了正确的JSON,但是相同的值ID 1被重复了:

[{“ID”:“1”,“NAME”:“John Doe”},
{“ID”:“1”,“NAME”:“John Doe”}]

应该是不同的值:

[{“ID”:“1”,“NAME”:“John Doe”},
{“ID”:“2”,“NAME”:“Jane Doe”}]

有谁知道哪里出问题了吗?

var arr []map[string]interface{}
for rows.Next() {
    err = rows.Scan(vals...)
    m := make(map[string]interface{})
    for i, v := range vals {
        m[colnames[i]] = v
    }
    str, _ := json.Marshal(m)
    fmt.Println(string(str))
    arr = append(arr, m)
}
json, _ := json.Marshal(arr)
fmt.Println(string(json))

我没有编写测试代码,所以很好奇为什么它总是返回相同的数据。 在下面的代码中,我认为每次调用都会创建一个映射

实际上,映射中的数据正确显示,然后映射(新指针)被添加到切片中,因此不可能重写它。但是,当写入切片时,只显示最后一个

对此有什么提示吗? 问候

var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()
colnames, _ := rows.Columns()
vals := make([]interface{}, len(cols))

for i, _ := range cols {  //bytes to string
   vals[i] = &cols[i]
}

mymap := make(map[string]interface{})

for i, v := range vals {  //adding column names
  mymap[colnames[i]] = v
}

for rows.Next() {
   err = rows.Scan(vals...)
   json, _ := json.Marshal(mymap)
   fmt.Fprintf(w,"%s\n",json)
}

这段代码能生成正确的JSON,但会重复相同的值ID 1:

[{“ID”:“1”,“NAME”:“John Doe”}, {“ID”:“1”,“NAME”:“John Doe”}]

实际发生的情况是:

第一行:{“ID”:“1”,“NAME”: "John } 第二行:{“ID”:“2”,“NAME”: “Jane Doe”}, {“ID”:“2”,“NAME”: “Jane Doe”} 第三行:{“ID”:“3”,“NAME”: “Donald Duck”},{“ID”:“3”,“NAME”: “Donald Duck”},{“ID”:“3”,“NAME”: “Donald Duck”}

rows.Scan能获取正确的值,但它会追加并替换所有之前的值。

有没有办法在遍历行时不替换之前的值?

这是一个常见的数据序列化问题。你需要将所有行数据收集到一个切片中,然后对整个切片进行JSON序列化。以下是正确的实现方式:

var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()

// 创建结果切片
var results []map[string]interface{}

for rows.Next() {
    // 为每一行创建新的值切片
    vals := make([]interface{}, len(cols))
    for i := range cols {
        vals[i] = new(interface{})
    }
    
    err = rows.Scan(vals...)
    if err != nil {
        // 处理错误
        continue
    }
    
    // 创建当前行的映射
    rowMap := make(map[string]interface{})
    for i, col := range cols {
        // 解引用interface{}指针获取实际值
        val := *(vals[i].(*interface{}))
        
        // 处理不同类型的数据
        switch v := val.(type) {
        case []byte:
            rowMap[col] = string(v)
        default:
            rowMap[col] = v
        }
    }
    
    // 将行数据添加到结果切片
    results = append(results, rowMap)
}

// 序列化整个结果集
jsonData, err := json.Marshal(results)
if err != nil {
    // 处理序列化错误
    fmt.Fprintf(w, "Error: %s", err)
    return
}

fmt.Fprintf(w, "%s", jsonData)

这个实现会输出你期望的JSON数组格式:

[{"ID":"1","NAME":"John Doe"},{"ID":"2","NAME":"Jane Doe"}]

关键点:

  • 使用 []map[string]interface{} 来存储所有行数据
  • 在循环中为每一行创建新的 vals 切片,避免数据覆盖
  • 使用类型断言正确处理 []byte 类型的数据
  • 最后对整个结果切片进行序列化

如果你想要更简洁的版本,也可以这样实现:

var results []map[string]string
cols, _ := rows.Columns()

for rows.Next() {
    vals := make([]interface{}, len(cols))
    for i := range cols {
        vals[i] = new(sql.NullString)
    }
    
    rows.Scan(vals...)
    
    rowMap := make(map[string]string)
    for i, col := range cols {
        if ns, ok := vals[i].(*sql.NullString); ok && ns.Valid {
            rowMap[col] = ns.String
        }
    }
    
    results = append(results, rowMap)
}

jsonData, _ := json.Marshal(results)
fmt.Fprintf(w, "%s", jsonData)
回到顶部