beego orm 不支持 mongodb,因其基于 sql 设计,而 mongodb 是无模式文档数据库;需用 mgo.v2 或 mongo-go-driver 手动集成,并正确处理 _id、bson/json 标签及连接复用。

Beego 本身不内置 MongoDB 支持,必须通过 mgo.v2(已归档但仍是主流选择)或更现代的 mongo-go-driver 手动集成;直接用 Beego ORM 无法操作 MongoDB —— 它只支持 MySQL/PostgreSQL/SQLite。
为什么 Beego 不能用 ORM 操作 MongoDB
Beego 的 orm 包基于 SQL 抽象层设计,所有方法(如 Insert()、QueryTable())都依赖表结构、主键约束、SQL 语法和事务模型。MongoDB 是无模式文档数据库,没有表、列、JOIN 或标准 SQL,因此 orm.RegisterModel() 对 struct 的注册在 MongoDB 场景下完全失效。
常见误操作是照搬 MySQL 示例,在 models/model.go 中调用 orm.RegisterModel(&User{}) 后尝试 o.Insert(),结果报错 unsupport driver "mongodb" 或 panic:nil pointer —— 因为底层驱动未初始化,ORM 根本没连上 MongoDB。
- Beego ORM 只识别
mysql、postgres、sqlite3三种驱动名 -
orm.RunSyncdb()在 MongoDB 下无意义:不存在“同步建表”概念 - 若强行配置
driverName = "mongodb",启动时会直接 panic
用 mgo.v2 连接并复用 Beego 配置
推荐使用 mgo.v2(兼容 Go 1.26+,社区仍在维护 fork 版本),它轻量、稳定,且与 Beego 生命周期易对齐。连接应放在 main.go 初始化阶段,避免每次请求新建 session。
在 conf/app.conf 中添加:
mongo_url = mongodb://localhost:27017 mongo_db = myapp
在 main.go 中初始化全局 *mgo.Database:
var Mongodb *mgo.Database
func main() {
if err := beego.LoadAppConfig("ini", "conf/app.conf"); err != nil {
panic(err)
}
url := beego.AppConfig.String("mongo_url")
dbName := beego.AppConfig.String("mongo_db")
session, err := mgo.DialWithTimeout(url, 5*time.Second)
if err != nil {
panic(err)
}
Mongodb = session.DB(dbName)
}
- 不要在 controller 里每次调用
mgo.Dial():连接池开销大,易触发too many open files -
Mongodb是线程安全的,可全局复用;但*mgo.Collection不是,需按需获取 - 若用副本集,
mongo_url应为mongodb://host1:27017,host2:27017/myapp?replicaSet=rs0
CRUD 操作必须显式处理 _id 和 struct 标签
从 MongoDB 读出的文档,_id 字段默认是 ObjectId 类型,Go 结构体中必须用 ObjectId 或字符串接收,且 bson 和 json 标签缺一不可 —— 否则查得到数据,API 返回却是空字段。
正确结构体示例:
type User struct {
Id bson.ObjectId `bson:"_id,omitempty" json:"_id,omitempty"`
Name string `bson:"name" json:"name"`
Email string `bson:"email" json:"email"`
Created time.Time `bson:"created" json:"created"`
}
-
bson:"_id,omitempty"确保插入时不传_id则自动生成;查询时能正确映射 -
json:"_id,omitempty"让 API 返回时保留_id字符串(bson.ObjectId.Hex()会被自动转) - 若用
string接收_id,必须手动调用ObjectIdHex(id)转换,否则FindId()失败 - 更新操作必须用
bson.M{"$set": ...},不能直接传 struct —— 否则会覆盖整个文档(包括_id)
Beego Controller 中安全执行 MongoDB 查询
在 controller 方法中,不要直接用全局 Mongodb 调 C("users").Find(...),因为 *mgo.Database 不保证并发安全(底层 session 可能被其他 goroutine 关闭)。应每次从 session 复制一个新 session,或封装工具函数。
推荐写法(在 controller 内):
func (c *UserController) Get() {
session := models.Mongodb.Session.Copy()
defer session.Close()
col := session.DB("").C("users")
var users []models.User
err := col.Find(bson.M{"status": "active"}).All(&users)
if err != nil {
c.Data["json"] = map[string]string{"error": err.Error()}
c.ServeJSON()
return
}
c.Data["json"] = users
c.ServeJSON()
}
-
session.Copy()是 cheap 的,开销远小于Dial();defer session.Close()必须有,否则连接泄漏 - 不要省略
err检查:MongoDB 网络超时、权限拒绝、字段类型不匹配都会返回具体错误,比如no documents in result或invalid ObjectId - 批量操作(如
Insert()数组)要控制数量,mgo默认单次最多 1000 条,超限需分片
最易被忽略的是:MongoDB 的 _id 类型和 Beego JSON 渲染之间的隐式转换链 —— 从 bson.ObjectId 到 struct 字段,再到 json.Marshal,最后到 Beego 的 ServeJSON(),任一环标签缺失或类型不匹配,就只剩空响应。别假设“结构体字段名和数据库字段名一样就能自动映射”。











