fiber整合mongodb的核心在mongo-go-driver的初始化、上下文控制和资源释放:连接需带超时context,结构体必须用bson tag,游标必须close,updateone参数顺序不能颠倒,client须全局复用。

直接上结论:Fiber 整合 MongoDB 的核心不在 Fiber,而在 mongo-go-driver 的初始化、上下文控制和资源释放方式;Fiber 只负责把 HTTP 请求路由到对应 handler,真正连库、查库、关游标这些事,全靠驱动层写对。
mongo-go-driver 连接必须带超时 context,不能用 context.TODO()
常见错误是写成 client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri)),这会导致连接卡死或 panic。生产环境必须显式设超时,并验证连通性。
- 用
context.WithTimeout(ctx, 10*time.Second)包裹 Connect 和 Ping 操作 -
client.Ping()必须传新 context(不能复用 Connect 时的),否则超时逻辑失效 - 连接池参数要显式配置:
options.Client().SetMaxPoolSize(20).SetMinPoolSize(5).SetConnectTimeout(5 * time.Second) - URI 务必从环境变量读取,如
os.Getenv("MONGODB_URI"),避免硬编码 localhost 或密码泄露
结构体字段必须用 bson tag,不是 json tag
Go 结构体映射 BSON 文档完全依赖 bson tag,漏写、拼错或类型不匹配,FindOne 就返回空值但不报错——这是最隐蔽的 bug 来源。
- ID 字段必须写成
ID primitive.ObjectID `bson:"_id,omitempty"`,下划线不能少,“omitempty”影响插入时是否生成新 _id - 时间字段类型必须是
time.Time,tag 写成bson:"created_at",不能是字符串或 int64 - 嵌套结构体每一层都要加
bsontag,否则子字段不会被序列化/反序列化 - 如果用
bson.M手动构造查询条件,key 是字符串,value 类型必须和数据库字段一致(比如"age": 25不能写成"age": "25")
Find() 游标必须 Close,且 defer 要绑定当前请求 context
Find() 返回的 *mongo.Cursor 底层持有网络连接和缓冲区,不 Close 就会泄漏 goroutine 和内存,尤其在高并发下很快 OOM。
- 必须写
defer cursor.Close(ctx),这里的ctx应该是 handler 入参的请求生命周期 context,不是全局 context - 遍历游标必须先
cursor.Next(),再cursor.Decode();跳过 Next 直接 Decode 会 panic - 批量结果可用
cursor.All()转切片,但要注意内存占用;流式处理更安全,适合大结果集 - 解码出错时,
cursor.Err()才返回非 nil 错误,不能只检查Next()返回值
UpdateOne 的 filter 和 update 参数顺序不能颠倒
这是新手高频翻车点:collection.UpdateOne(ctx, filter, update),filter 在前、update 在后。写反了不会编译报错,但 update 会被当 filter 解析,导致查不到文档、更新零条,还看不出问题。
- filter 建议用
bson.M{"_id": id}或bson.D{{"_id", id}},别混用 map 和 slice - update 操作符必须带
$set、$inc等前缀,比如bson.M{"$set": bson.M{"name": "foo"}} - 更新后想获取修改前/后的文档,要用
FindOneAndUpdate()并传options.FindOneAndUpdate().SetReturnDocument(options.Before)
最容易被忽略的是 Client 全局复用、Collection 不缓存——client.Database("db").Collection("users") 每次调用都只是轻量对象创建,无需 cache;但 client 必须是单例,否则连接池失控。还有,Prefork 模式下各进程独立内存,别在 handler 里用包级变量存 client 或 collection 实例。











