
本文详细讲解如何使用 mgo(v2)驱动在 go 中构造 mongodb 的 `$or` 逻辑查询,包括语法结构、完整可运行示例、常见陷阱及注意事项。
在 MongoDB 的原生 Shell 中,$or 是一个非常常用的逻辑操作符,用于匹配满足任一子条件的文档。迁移到 Go 生态时,mgo(gopkg.in/mgo.v2)通过 bson.M 映射结构来表达这类查询。其核心在于:$or 的值必须是一个 []bson.M 切片,每个元素都是一个独立的条件对象(即 bson.M)。
✅ 正确写法如下:
conditions := bson.M{
"$or": []bson.M{
bson.M{"uuid": "UUID0"},
bson.M{"name": "Joe"},
},
}该结构严格对应 MongoDB 的 JSON 查询格式 {"$or": [{"uuid":"UUID0"}, {"name":"Joe"}]},语义为“查找 uuid 等于 "UUID0" 或 name 等于 "Joe" 的任意一条文档”。
⚠️ 常见错误需避免:
- 使用 []interface{} 替代 []bson.M(如 []interface{}{bson.M{"uuid":x}, bson.M{"name":x}}),会导致序列化失败或空结果;
- 混淆嵌套层级,例如将 $or 错误置于外层 bson.M 的键名位置之外;
- 忘记导入 "gopkg.in/mgo.v2/bson" 包,导致 bson.M 类型未定义。
下面是一个完整、可直接运行的示例程序,包含连接、建表、插入测试数据与执行 $or 查询全流程:
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{Num: 1, Uuid: "UUID1", Name: "Joe"},
&Person{Num: 2, Uuid: "UUID2", Name: "Jane"},
&Person{Num: 3, Uuid: "UUID3", Name: "Didier"},
); err != nil {
log.Fatal(err)
}
// 执行 $or 查询:匹配 uuid=="UUID1" 或 name=="Jane"
var result Person
query := bson.M{
"$or": []bson.M{
bson.M{"uuid": "UUID1"},
bson.M{"name": "Jane"},
},
}
if err = c.Find(query).One(&result); err != nil {
log.Fatal("查询失败:", err)
}
fmt.Printf("匹配到文档: %+v\n", result) // 输出: {Num:1 Uuid:"UUID1" Name:"Joe"}
}? 补充说明:
- 若需查询多条匹配结果,请使用 All() 方法替代 One(),并传入 []Person{} 切片;
- $or 查询在大数据集上可能影响性能(尤其当各子条件字段未建立索引时),建议对参与 $or 的每个字段(如 uuid 和 name)分别创建单字段索引;
- mgo 已进入维护模式,新项目推荐迁移至官方驱动 mongo-go-driver,其 $or 写法为 bson.D{{"$or", bson.A{bson.D{{"uuid", "UUID0"}}, bson.D{{"name", "Joe"}}}}},但本文聚焦 mgo 场景。
掌握 bson.M{"$or": []bson.M{...}} 这一范式,即可安全、高效地在 mgo 中实现多条件逻辑查询。











