如何在 Go 的 mgo 驱动中正确构建 $or 查询条件

本文详解如何使用 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 查询的基础能力——它让“任一条件满足即命中”的业务逻辑(如多字段模糊搜索、复合权限校验)得以简洁实现。