
本文详解如何使用 mgo(v2)在 go 中正确构造 mongodb 的 `$or` 逻辑查询,包括语法结构、完整可运行示例及常见注意事项。
在 MongoDB 的原生 Shell 中,$or 操作符用于匹配满足任一子条件的文档,例如 {"$or": [{"uuid": "bar"}, {"name": "bar"}]}。迁移到 Go 的 mgo 驱动时,关键在于准确映射嵌套的 BSON 结构:$or 的值必须是一个 []bson.M 切片,每个元素为独立的 bson.M 条件对象。
正确的构造方式如下:
conditions := bson.M{
"$or": []bson.M{
bson.M{"uuid": foo},
bson.M{"name": foo},
},
}注意:切片内每个条件必须是 bson.M(即 map[string]interface{}),不能写成 bson.M{"uuid": foo, "name": foo}(这是 AND 逻辑),也不能遗漏方括号或误用花括号。
以下是一个完整、可直接运行的示例程序,包含连接、数据插入与 $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(fmt.Sprintf("连接 MongoDB 失败: %v", 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=="UUID0" 或 name=="Joe" 的文档
var result Person
err = c.Find(bson.M{
"$or": []bson.M{
bson.M{"uuid": "UUID0"}, // 不匹配
bson.M{"name": "Joe"}, // 匹配 → 返回第一条
},
}).One(&result)
if err != nil {
log.Fatal("查询失败:", err)
}
fmt.Printf("匹配结果: %+v\n", result) // 输出: {Num:1 Uuid:"UUID1" Name:"Joe"}
}✅ 关键要点总结:
- $or 必须作为顶层键,其值为 []bson.M(切片),不可为 bson.M 或 []interface{};
- 每个子条件 bson.M 内部是独立的字段匹配,互不干扰;
- 若需组合 $or 与其他条件(如 {"status": "active"}),可将其合并到同一 bson.M 中:bson.M{"status": "active", "$or": [...]} —— 表示“status 为 active 且 (uuid 或 name 匹配)”;
- mgo 已归档(官方推荐迁移至 mongo-go-driver),新项目应优先考虑现代驱动;若维护旧代码,请确保使用 gopkg.in/mgo.v2 并注意其线程安全限制(session 需 .Copy() 后在 goroutine 中使用)。
正确理解并实践这一结构,即可灵活实现多字段“或”逻辑查询,大幅提升 Go 应用与 MongoDB 的交互能力。










