
本文介绍如何使用 Go 的 mgo 驱动从 MongoDB 查询结构化数据,并将其动态转换为纯键值对格式的 JSON 对象(如 {"key1":"val1","key2":"val2"}),而非默认的结构体数组形式。
本文介绍如何使用 go 的 mgo 驱动从 mongodb 查询结构化数据,并将其动态转换为纯键值对格式的 json 对象(如 {"key1":"val1","key2":"val2"}),而非默认的结构体数组形式。
在使用 mgo 操作 MongoDB 时,常见误区是直接对结构体切片调用 json.MarshalIndent,这会生成标准的 JSON 数组格式(如 [{"Endpoint":"/api/endpoint1","Time":"0.8s"}])。但若业务需要的是以 Endpoint 为键、Time 为值的扁平化映射对象(即无外层方括号、无字段名嵌套),则需手动构造 JSON 输出。
首先,确保查询结果按 Endpoint 字段有序,避免键序不确定带来的可读性与一致性问题:
var results []Slow
err := collection.Find(nil).Sort("Endpoint").All(&results)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
⚠️ 注意:MongoDB 默认不保证查询顺序,
Sort("Endpoint")显式排序是生成确定性键序的前提。
接着,跳过 json.Marshal,改用流式写入方式构建目标 JSON 格式。以下代码精确输出符合要求的缩进键值对对象(无数组、无冗余字段名):
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
w.Header().Set("Content-Type", "application/json")
w.Write([]byte{'{'})
for i, slow := range results {
if i > 0 {
w.Write([]byte{','})
}
// 使用
实现换行与缩进,保持可读性
w.Write([]byte(fmt.Sprintf("
"%s":"%s"",
strings.ReplaceAll(slow.Endpoint, """, "\""),
strings.ReplaceAll(slow.Time, """, "\""))))
}
w.Write([]byte("
}"))
✅ 关键细节说明:
- 使用
strings.ReplaceAll转义双引号,防止非法 JSON(如Time中含"0.8s"本身安全,但健壮性需覆盖任意字符串); - 手动控制逗号分隔与换行缩进,替代
json.MarshalIndent的数组封装逻辑; - 设置
Content-Type: application/json确保客户端正确解析。
? 替代方案(更灵活):若后续需扩展字段或复用逻辑,可先构建 map[string]string,再统一序列化:
m := make(map[string]string)
for _, s := range results {
m[s.Endpoint] = s.Time
}
data, _ := json.Marshal(m) // 自动输出 {"key1":"val1","key2":"val2"}
w.Header().Set("Content-Type", "application/json")
w.Write(data)
该方式语义清晰、易于维护,且 json.Marshal 会自动处理转义与格式,推荐在多数场景下优先采用。最终输出严格匹配预期:
{
"/api/endpoint1":"0.8s",
"/api/endpoint2":"0.7s"
}










