
本文详解如何使用 mgo(v2)驱动在 go 中构造 mongodb 的 `$or` 逻辑查询,包括语法结构、完整可运行示例及常见注意事项。
在 MongoDB 的 Go 生态中,mgo(虽已归档但仍在广泛维护的 v2 分支)是早期最常用的驱动之一。其查询语法高度贴近原生 BSON 表达,但初学者易在嵌套结构上出错。核心要点在于:$or 接收一个文档数组([]bson.M),每个元素均为独立的查询条件(bson.M),且各条件之间为逻辑“或”关系。
✅ 正确语法结构如下:
bson.M{
"$or": []bson.M{
bson.M{"uuid": "some-uuid"},
bson.M{"name": "John"},
bson.M{"email": bson.M{"$regex": "^test@.*\\.com$"}},
},
}⚠️ 常见错误包括:
- 将 []bson.M 误写为 []interface{} 或 []map[string]interface{}(类型不匹配,mgo 无法序列化);
- 混淆 $or 与 $in:$in 用于单字段匹配多个值(如 {"status": {"$in": ["active", "pending"]}}),而 $or 用于跨字段的多条件组合;
- 忘记导入 "gopkg.in/mgo.v2/bson"(仅导入 mgo 不够,bson.M 定义在此包中)。
以下是一个完整、可直接运行的示例(兼容 Go 1.4+ 和 MongoDB 2.6+):
package main
import (
"fmt"
"log"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type Person struct {
Num int `bson:"num"`
Uuid string `bson:"uuid"`
Name string `bson:"name"`
}
func main() {
session, err := mgo.Dial("localhost:27017")
if err != nil {
panic(err)
}
defer session.Close()
c := session.DB("test").C("people")
// 清理测试环境
c.DropCollection()
// 插入测试数据
if err = c.Insert(
&Person{1, "UUID1", "Joe"},
&Person{2, "UUID2", "Jane"},
&Person{3, "UUID3", "Didier"},
); err != nil {
log.Fatal(err)
}
// 构造 $or 查询:查找 uuid="UUID0" OR name="Joe"
query := bson.M{
"$or": []bson.M{
bson.M{"uuid": "UUID0"},
bson.M{"name": "Joe"},
},
}
var result Person
if err = c.Find(query).One(&result); err != nil {
log.Printf("No match found (expected for UUID0): %v", err)
// 注意:此处因 UUID0 不存在,会返回 mgo.ErrNotFound,属正常行为
return
}
fmt.Printf("Found: %+v\n", result) // 输出: Found: {Num:1 Uuid:"UUID1" Name:"Joe"}
}? 关键提示:
- 若需查询全部匹配项,用 All(&[]Person{}) 替代 One(&Person{});
- 在生产环境中,建议对 c.Find() 加 .Sort()、.Limit() 或 .Select() 优化性能;
- mgo 已不再积极维护,新项目推荐迁移到官方驱动 mongo-go-driver,其 $or 写法为 bson.D{{"$or", bson.A{bson.D{{"uuid", "x"}}, bson.D{{"name", "y"}}}}},语义一致但类型更严格。
掌握 $or 的正确构造方式,是编写灵活、高效 MongoDB 查询的基础能力——它让“任一条件满足即命中”的业务逻辑(如多字段模糊搜索、复合权限校验)得以简洁实现。











