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

本文详解如何使用 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 的交互能力。