文档模型与 mongosh

安装与连接

# macOS
brew tap mongodb/brew && brew install mongodb-community && brew services start mongodb-community

# Docker(推荐)
docker run -d --name mongo -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=secret \
  mongo:7
mongosh "mongodb://admin:secret@127.0.0.1:27017/demo"

mongosh 常用命令:

show dbs                  // 列出数据库
use demo                  // 切换/创建数据库
show collections          // 列出集合
db.users.find().pretty()  // 查询
db.users.stats()          // 集合统计
db.users.drop()           // 删除集合

BSON 与文档

MongoDB 底层用 BSON(Binary JSON)存储,扩展了 JSON 的类型:

类型说明
ObjectId12 字节的默认主键 _id,含时间戳、机器与计数器
String / Int32 / Int64 / Double / Decimal128数值与文本
DateUTC 毫秒时间戳
Boolean / Null布尔与空
Array数组
Object嵌套文档
Binary / Regex / Timestamp其他
db.users.insertMany([
  {
    _id: ObjectId(),
    name: "Alice",
    email: "alice@example.com",
    address: { city: "北京" },
    tags: ["vip", "new"],
    balance: NumberDecimal("99.50"),
    createdAt: new Date()
  }
])
Tip

金额在 MongoDB 中应使用 Decimal128NumberDecimal),而非 Double,以避免浮点误差。Go 端对应 primitive.Decimal128

集合与命名

  • 集合相当于关系型的表,但不强制 schema
  • 集合名区分大小写,建议清晰命名(复数、小写)。
  • 可通过校验器约束文档结构:
db.createCollection("accounts", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["email", "balance"],
      properties: {
        email:   { bsonType: "string" },
        balance: { bsonType: "decimal" },
        status:  { enum: ["active", "frozen"] }
      }
    }
  }
})

用 Go 连接 MongoDB

go get go.mongodb.org/mongo-driver/mongo
package main

import (
    "context"
    "log"
    "time"

    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type User struct {
    ID        string    `bson:"_id,omitempty"`
    Name      string    `bson:"name"`
    Email     string    `bson:"email"`
    CreatedAt time.Time `bson:"createdAt"`
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    uri := "mongodb://admin:secret@127.0.0.1:27017/?authSource=admin"
    client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
    if err != nil {
        log.Fatal(err)
    }
    defer func() { _ = client.Disconnect(ctx) }()

    if err := client.Ping(ctx, nil); err != nil {
        log.Fatal("连接失败:", err)
    }

    coll := client.Database("demo").Collection("users")

    _, err = coll.InsertOne(ctx, User{Name: "Alice", Email: "alice@example.com", CreatedAt: time.Now()})
    if err != nil {
        log.Fatal(err)
    }

    var u User
    if err := coll.FindOne(ctx, bson.M{"email": "alice@example.com"}).Decode(&u); err != nil {
        log.Fatal(err)
    }
    log.Printf("%+v", u)
}
Warning

mongo.Connect惰性的,不会立即建立连接,务必用 Ping 验证。mongo.Client 应作为长生命周期单例复用(内部维护连接池),不要每次请求都新建。

小结

  • MongoDB 以 BSON 文档存储,_id 默认由 ObjectId 生成。
  • 建模核心是「嵌入 vs 引用」,并警惕 16MB 文档上限与无界数组。
  • 灵活 schema 需要用校验器或应用层约束兜底。
  • Go 使用官方 mongo-driver,复用客户端并 Ping 验证连接。