Go Mongo
MongoDB 是一个流行的 NoSQL 文档数据库,使用 BSON(Binary JSON)格式存储数据。与关系型数据库不同,MongoDB 具有灵活的模式设计,适合存储非结构化或半结构化数据。
官方提供了 Go 语言 MongoDB 驱动程序 go.mongodb.org/mongo-driver。
下面是一个示例:
package main
import (
"context"
"fmt"
"log"
"math/rand"
"os"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 1. 数据模型定义
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
Name string `bson:"name" json:"name"`
Email string `bson:"email" json:"email"`
Age int `bson:"age" json:"age"`
Address Address `bson:"address" json:"address"`
Tags []string `bson:"tags" json:"tags"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
}
type Address struct {
Street string `bson:"street" json:"street"`
City string `bson:"city" json:"city"`
Country string `bson:"country" json:"country"`
}
type Product struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
Name string `bson:"name" json:"name"`
Price float64 `bson:"price" json:"price"`
Description string `bson:"description" json:"description"`
Category string `bson:"category" json:"category"`
Stock int `bson:"stock" json:"stock"`
IsActive bool `bson:"is_active" json:"is_active"`
Attributes map[string]interface{} `bson:"attributes" json:"attributes"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
}
type Order struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
UserID primitive.ObjectID `bson:"user_id" json:"user_id"`
Items []OrderItem `bson:"items" json:"items"`
Total float64 `bson:"total" json:"total"`
Status string `bson:"status" json:"status"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
}
type OrderItem struct {
ProductID primitive.ObjectID `bson:"product_id" json:"product_id"`
Name string `bson:"name" json:"name"`
Quantity int `bson:"quantity" json:"quantity"`
Price float64 `bson:"price" json:"price"`
}
// 2. MongoDB 服务
type MongoDB struct {
Client *mongo.Client
Database *mongo.Database
}
func NewMongoDB(uri, dbName string) (*MongoDB, error) {
// 设置连接选项
clientOptions := options.Client().
ApplyURI(uri).
SetMaxPoolSize(100).
SetMinPoolSize(10).
SetMaxConnIdleTime(5 * time.Minute)
// 连接 MongoDB
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
return nil, fmt.Errorf("连接 MongoDB 失败: %v", err)
}
// 测试连接
err = client.Ping(ctx, nil)
if err != nil {
return nil, fmt.Errorf("MongoDB 连接测试失败: %v", err)
}
database := client.Database(dbName)
fmt.Println("✅ MongoDB 连接成功")
return &MongoDB{
Client: client,
Database: database,
}, nil
}
func (m *MongoDB) Close() error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
return m.Client.Disconnect(ctx)
}
func (m *MongoDB) GetCollection(name string) *mongo.Collection {
return m.Database.Collection(name)
}
// 3. 基本 CRUD 操作示例
func demonstrateBasicCRUD(mongoDB *MongoDB) {
fmt.Println("\n=== 基本 CRUD 操作 ===")
usersCollection := mongoDB.GetCollection("users")
ctx := context.Background()
// 创建用户
fmt.Println("\n1. 插入文档:")
user := User{
Name: "张三",
Email: "zhang@example.com",
Age: 25,
Address: Address{Street: "人民路123号", City: "北京", Country: "中国"},
Tags: []string{"vip", "active"},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
result, err := usersCollection.InsertOne(ctx, user)
if err != nil {
log.Printf("插入用户失败: %v", err)
return
}
userID := result.InsertedID.(primitive.ObjectID)
fmt.Printf("创建用户成功,ID: %s\n", userID.Hex())
// 查询单个文档
fmt.Println("\n2. 查询单个文档:")
var fetchedUser User
err = usersCollection.FindOne(ctx, bson.M{"email": "zhang@example.com"}).Decode(&fetchedUser)
if err != nil {
log.Printf("查询用户失败: %v", err)
return
}
fmt.Printf("查询结果: %s (%s), 年龄: %d\n", fetchedUser.Name, fetchedUser.Email, fetchedUser.Age)
// 查询多个文档
fmt.Println("\n3. 查询多个文档:")
cursor, err := usersCollection.Find(ctx, bson.M{})
if err != nil {
log.Printf("查询用户列表失败: %v", err)
return
}
defer cursor.Close(ctx)
var users []User
if err = cursor.All(ctx, &users); err != nil {
log.Printf("解析用户列表失败: %v", err)
return
}
fmt.Println("所有用户:")
for _, u := range users {
fmt.Printf(" - ID: %s, 姓名: %s, 邮箱: %s\n", u.ID.Hex(), u.Name, u.Email)
}
// 更新文档
fmt.Println("\n4. 更新文档:")
update := bson.M{
"$set": bson.M{
"age": 26,
"updated_at": time.Now(),
},
}
updateResult, err := usersCollection.UpdateOne(
ctx,
bson.M{"_id": userID},
update,
)
if err != nil {
log.Printf("更新用户失败: %v", err)
return
}
fmt.Printf("更新成功,影响文档数: %d\n", updateResult.ModifiedCount)
// 删除文档
fmt.Println("\n5. 删除文档:")
deleteResult, err := usersCollection.DeleteOne(ctx, bson.M{"_id": userID})
if err != nil {
log.Printf("删除用户失败: %v", err)
return
}
fmt.Printf("删除成功,删除文档数: %d\n", deleteResult.DeletedCount)
}
// 4. 高级查询示例
func demonstrateAdvancedQueries(mongoDB *MongoDB) {
fmt.Println("\n=== 高级查询示例 ===")
productsCollection := mongoDB.GetCollection("products")
ctx := context.Background()
// 创建测试数据
products := []interface{}{
Product{
Name: "MacBook Pro",
Price: 12999.99,
Description: "苹果笔记本电脑",
Category: "electronics",
Stock: 50,
IsActive: true,
Attributes: map[string]interface{}{"brand": "Apple", "color": "Silver"},
CreatedAt: time.Now(),
},
Product{
Name: "iPhone 14",
Price: 5999.99,
Description: "苹果手机",
Category: "electronics",
Stock: 100,
IsActive: true,
Attributes: map[string]interface{}{"brand": "Apple", "storage": "128GB"},
CreatedAt: time.Now(),
},
Product{
Name: "咖啡机",
Price: 899.99,
Description: "家用咖啡机",
Category: "appliances",
Stock: 30,
IsActive: true,
Attributes: map[string]interface{}{"brand": "Nespresso", "type": "automatic"},
CreatedAt: time.Now(),
},
}
_, err := productsCollection.InsertMany(ctx, products)
if err != nil {
log.Printf("插入产品失败: %v", err)
return
}
// 条件查询
fmt.Println("\n1. 条件查询:")
var expensiveProducts []Product
cursor, err := productsCollection.Find(
ctx,
bson.M{"price": bson.M{"$gt": 5000}},
options.Find().SetSort(bson.M{"price": -1}),
)
if err != nil {
log.Printf("查询高价产品失败: %v", err)
return
}
defer cursor.Close(ctx)
if err = cursor.All(ctx, &expensiveProducts); err != nil {
log.Printf("解析产品失败: %v", err)
return
}
fmt.Println("价格大于5000的产品:")
for _, p := range expensiveProducts {
fmt.Printf(" - %s: ¥%.2f\n", p.Name, p.Price)
}
// 数组查询
fmt.Println("\n2. 数组查询:")
var usersWithTag []User
usersCollection := mongoDB.GetCollection("users")
cursor, err = usersCollection.Find(
ctx,
bson.M{"tags": bson.M{"$in": []string{"vip", "premium"}}},
)
if err != nil {
log.Printf("查询标签用户失败: %v", err)
return
}
defer cursor.Close(ctx)
if err = cursor.All(ctx, &usersWithTag); err != nil {
log.Printf("解析用户失败: %v", err)
return
}
fmt.Println("VIP 或 Premium 用户:")
for _, u := range usersWithTag {
fmt.Printf(" - %s: %v\n", u.Name, u.Tags)
}
// 投影查询(只返回指定字段)
fmt.Println("\n3. 投影查询:")
type ProductNameOnly struct {
Name string `bson:"name"`
Price float64 `bson:"price"`
}
var productNames []ProductNameOnly
cursor, err = productsCollection.Find(
ctx,
bson.M{},
options.Find().SetProjection(bson.M{"name": 1, "price": 1}),
)
if err != nil {
log.Printf("投影查询失败: %v", err)
return
}
defer cursor.Close(ctx)
if err = cursor.All(ctx, &productNames); err != nil {
log.Printf("解析投影结果失败: %v", err)
return
}
fmt.Println("产品名称和价格:")
for _, p := range productNames {
fmt.Printf(" - %s: ¥%.2f\n", p.Name, p.Price)
}
}
// 5. 聚合管道示例
func demonstrateAggregation(mongoDB *MongoDB) {
fmt.Println("\n=== 聚合管道示例 ===")
ordersCollection := mongoDB.GetCollection("orders")
ctx := context.Background()
// 创建测试订单数据
orders := []interface{}{
Order{
UserID: primitive.NewObjectID(),
Items: []OrderItem{
{ProductID: primitive.NewObjectID(), Name: "MacBook Pro", Quantity: 1, Price: 12999.99},
{ProductID: primitive.NewObjectID(), Name: "iPhone", Quantity: 2, Price: 5999.99},
},
Total: 24999.97,
Status: "completed",
CreatedAt: time.Now().AddDate(0, 0, -5),
},
Order{
UserID: primitive.NewObjectID(),
Items: []OrderItem{
{ProductID: primitive.NewObjectID(), Name: "iPad", Quantity: 1, Price: 4399.99},
},
Total: 4399.99,
Status: "completed",
CreatedAt: time.Now().AddDate(0, 0, -3),
},
Order{
UserID: primitive.NewObjectID(),
Items: []OrderItem{
{ProductID: primitive.NewObjectID(), Name: "MacBook Pro", Quantity: 1, Price: 12999.99},
},
Total: 12999.99,
Status: "pending",
CreatedAt: time.Now().AddDate(0, 0, -1),
},
}
_, err := ordersCollection.InsertMany(ctx, orders)
if err != nil {
log.Printf("插入订单失败: %v", err)
return
}
// 聚合查询:按状态统计订单数量和总金额
fmt.Println("\n1. 按状态统计订单:")
pipeline := bson.A{
bson.M{
"$group": bson.M{
"_id": "$status",
"count": bson.M{"$sum": 1},
"total_amount": bson.M{"$sum": "$total"},
"avg_amount": bson.M{"$avg": "$total"},
},
},
bson.M{
"$sort": bson.M{"total_amount": -1},
},
}
cursor, err := ordersCollection.Aggregate(ctx, pipeline)
if err != nil {
log.Printf("聚合查询失败: %v", err)
return
}
defer cursor.Close(ctx)
type OrderStats struct {
Status string `bson:"_id"`
Count int `bson:"count"`
TotalAmount float64 `bson:"total_amount"`
AvgAmount float64 `bson:"avg_amount"`
}
var stats []OrderStats
if err = cursor.All(ctx, &stats); err != nil {
log.Printf("解析聚合结果失败: %v", err)
return
}
fmt.Println("订单统计:")
for _, s := range stats {
fmt.Printf(" - 状态: %s, 数量: %d, 总金额: ¥%.2f, 平均金额: ¥%.2f\n",
s.Status, s.Count, s.TotalAmount, s.AvgAmount)
}
// 聚合查询:展开订单项统计产品销量
fmt.Println("\n2. 产品销量统计:")
salesPipeline := bson.A{
bson.M{"$unwind": "$items"},
bson.M{
"$group": bson.M{
"_id": "$items.name",
"total_sold": bson.M{"$sum": "$items.quantity"},
"total_revenue": bson.M{"$sum": bson.M{"$multiply": []interface{}{"$items.quantity", "$items.price"}}},
},
},
bson.M{"$sort": bson.M{"total_sold": -1}},
}
cursor, err = ordersCollection.Aggregate(ctx, salesPipeline)
if err != nil {
log.Printf("销量统计失败: %v", err)
return
}
defer cursor.Close(ctx)
type SalesStats struct {
ProductName string `bson:"_id"`
TotalSold int `bson:"total_sold"`
TotalRevenue float64 `bson:"total_revenue"`
}
var salesStats []SalesStats
if err = cursor.All(ctx, &salesStats); err != nil {
log.Printf("解析销量统计失败: %v", err)
return
}
fmt.Println("产品销量统计:")
for _, s := range salesStats {
fmt.Printf(" - %s: 销量 %d, 收入 ¥%.2f\n", s.ProductName, s.TotalSold, s.TotalRevenue)
}
}
// 6. 索引管理示例
func demonstrateIndexes(mongoDB *MongoDB) {
fmt.Println("\n=== 索引管理示例 ===")
usersCollection := mongoDB.GetCollection("users")
ctx := context.Background()
// 创建索引
fmt.Println("\n1. 创建索引:")
indexModels := []mongo.IndexModel{
{
Keys: bson.M{"email": 1},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.M{"created_at": -1},
},
{
Keys: bson.M{"age": 1, "city": 1}, // 复合索引
},
}
indexNames, err := usersCollection.Indexes().CreateMany(ctx, indexModels)
if err != nil {
log.Printf("创建索引失败: %v", err)
return
}
fmt.Printf("创建索引成功: %v\n", indexNames)
// 列出索引
fmt.Println("\n2. 列出索引:")
cursor, err := usersCollection.Indexes().List(ctx)
if err != nil {
log.Printf("列出索引失败: %v", err)
return
}
defer cursor.Close(ctx)
var indexes []bson.M
if err = cursor.All(ctx, &indexes); err != nil {
log.Printf("解析索引失败: %v", err)
return
}
fmt.Println("集合索引:")
for _, index := range indexes {
fmt.Printf(" - 名称: %v, 键: %v\n", index["name"], index["key"])
}
}
// 7. 事务处理示例
func demonstrateTransactions(mongoDB *MongoDB) {
fmt.Println("\n=== 事务处理示例 ===")
ctx := context.Background()
// 开始会话
session, err := mongoDB.Client.StartSession()
if err != nil {
log.Printf("开始会话失败: %v", err)
return
}
defer session.EndSession(ctx)
// 执行事务
err = session.StartTransaction()
if err != nil {
log.Printf("开始事务失败: %v", err)
return
}
callback := func(sessionContext mongo.SessionContext) (interface{}, error) {
usersCollection := mongoDB.GetCollection("users")
ordersCollection := mongoDB.GetCollection("orders")
// 创建用户
user := User{
Name: "事务用户",
Email: fmt.Sprintf("transaction%d@example.com", rand.Intn(1000)),
Age: 30,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
userResult, err := usersCollection.InsertOne(sessionContext, user)
if err != nil {
return nil, err
}
userID := userResult.InsertedID.(primitive.ObjectID)
// 创建订单
order := Order{
UserID: userID,
Items: []OrderItem{{Name: "测试产品", Quantity: 1, Price: 100}},
Total: 100,
Status: "completed",
CreatedAt: time.Now(),
}
_, err = ordersCollection.InsertOne(sessionContext, order)
if err != nil {
return nil, err
}
fmt.Printf("✅ 事务执行成功,创建用户 ID: %s\n", userID.Hex())
return userID, nil
}
// 提交事务
result, err := session.WithTransaction(ctx, callback)
if err != nil {
log.Printf("事务执行失败: %v", err)
session.AbortTransaction(ctx)
return
}
fmt.Printf("事务结果: %v\n", result)
}
// 8. 批量操作示例
func demonstrateBulkOperations(mongoDB *MongoDB) {
fmt.Println("\n=== 批量操作示例 ===")
usersCollection := mongoDB.GetCollection("users")
ctx := context.Background()
// 批量写入
fmt.Println("\n1. 批量插入:")
users := []interface{}{
User{Name: "批量用户1", Email: "batch1@example.com", Age: 20},
User{Name: "批量用户2", Email: "batch2@example.com", Age: 25},
User{Name: "批量用户3", Email: "batch3@example.com", Age: 30},
}
insertResult, err := usersCollection.InsertMany(ctx, users)
if err != nil {
log.Printf("批量插入失败: %v", err)
return
}
fmt.Printf("批量插入成功,插入 %d 个文档\n", len(insertResult.InsertedIDs))
// 批量更新
fmt.Println("\n2. 批量更新:")
filter := bson.M{"age": bson.M{"$lt": 30}}
update := bson.M{"$inc": bson.M{"age": 1}}
updateResult, err := usersCollection.UpdateMany(ctx, filter, update)
if err != nil {
log.Printf("批量更新失败: %v", err)
return
}
fmt.Printf("批量更新成功,更新 %d 个文档\n", updateResult.ModifiedCount)
// 批量删除
fmt.Println("\n3. 批量删除:")
deleteResult, err := usersCollection.DeleteMany(ctx, bson.M{"email": bson.M{"$regex": "batch"}})
if err != nil {
log.Printf("批量删除失败: %v", err)
return
}
fmt.Printf("批量删除成功,删除 %d 个文档\n", deleteResult.DeletedCount)
}
// 9. 监控和性能示例
func demonstrateMonitoring(mongoDB *MongoDB) {
fmt.Println("\n=== 数据库监控 ===")
ctx := context.Background()
// 获取数据库统计信息
statsCommand := bson.D{{Key: "dbStats", Value: 1}}
var stats bson.M
err := mongoDB.Database.RunCommand(ctx, statsCommand).Decode(&stats)
if err != nil {
log.Printf("获取数据库统计失败: %v", err)
return
}
fmt.Printf("数据库统计:\n")
fmt.Printf(" 数据库名: %v\n", stats["db"])
fmt.Printf(" 集合数: %v\n", stats["collections"])
fmt.Printf(" 文档数: %v\n", stats["objects"])
fmt.Printf(" 数据大小: %.2f MB\n", stats["dataSize"].(float64)/1024/1024)
fmt.Printf(" 存储大小: %.2f MB\n", stats["storageSize"].(float64)/1024/1024)
}
// 10. 文本搜索示例
func demonstrateTextSearch(mongoDB *MongoDB) {
fmt.Println("\n=== 文本搜索示例 ===")
productsCollection := mongoDB.GetCollection("products")
ctx := context.Background()
// 创建文本索引
fmt.Println("\n1. 创建文本索引:")
model := mongo.IndexModel{
Keys: bson.M{
"name": "text",
"description": "text",
},
}
_, err := productsCollection.Indexes().CreateOne(ctx, model)
if err != nil {
log.Printf("创建文本索引失败: %v", err)
return
}
// 文本搜索
fmt.Println("\n2. 文本搜索:")
cursor, err := productsCollection.Find(
ctx,
bson.M{"$text": bson.M{"$search": "苹果 电脑"}},
options.Find().SetProjection(bson.M{"score": bson.M{"$meta": "textScore"}}).
SetSort(bson.M{"score": bson.M{"$meta": "textScore"}}),
)
if err != nil {
log.Printf("文本搜索失败: %v", err)
return
}
defer cursor.Close(ctx)
var results []bson.M
if err = cursor.All(ctx, &results); err != nil {
log.Printf("解析搜索结果失败: %v", err)
return
}
fmt.Println("文本搜索结果:")
for _, result := range results {
fmt.Printf(" - %s (相关度: %.2f)\n", result["name"], result["score"])
}
}
func main() {
// MongoDB 连接字符串
// 本地 MongoDB: mongodb://localhost:27017
// MongoDB Atlas: mongodb+srv://username:password@cluster.mongodb.net/database
uri := "mongodb://localhost:27017"
if os.Getenv("MONGODB_URI") != "" {
uri = os.Getenv("MONGODB_URI")
}
dbName := "go_mongo_demo"
// 连接 MongoDB
mongoDB, err := NewMongoDB(uri, dbName)
if err != nil {
log.Fatal(err)
}
defer mongoDB.Close()
// 清空测试数据(可选)
ctx := context.Background()
collections := []string{"users", "products", "orders"}
for _, coll := range collections {
mongoDB.GetCollection(coll).Drop(ctx)
}
// 运行各种示例
demonstrateBasicCRUD(mongoDB)
demonstrateAdvancedQueries(mongoDB)
demonstrateAggregation(mongoDB)
demonstrateIndexes(mongoDB)
demonstrateTransactions(mongoDB)
demonstrateBulkOperations(mongoDB)
demonstrateMonitoring(mongoDB)
demonstrateTextSearch(mongoDB)
fmt.Println("\n🎉 所有 MongoDB 示例执行完成!")
}
MongoDB 关键特性
- 核心概念
文档 :BSON 格式的数据记录
集合 :文档的容器
数据库 :集合的容器
ObjectID:12 字节的唯一标识符
- 主要操作
插入 :InsertOne(), InsertMany()
查询 :FindOne(), Find()
更新 :UpdateOne(), UpdateMany()
删除 :DeleteOne(), DeleteMany()
- 查询操作符
比较 :$eq, $gt, $lt, $in
逻辑 :$and, $or, $not
数组 :$all, $elemMatch, $size
元素 :$exists, $type
- 聚合管道
$match:过滤文档
$group:分组统计
$sort:排序
$project:投影字段
$unwind:展开数组
- 最佳实践
连接池管理 :合理配置连接池参数
索引优化 :为常用查询字段创建索引
文档设计 :合理设计文档结构
错误处理 :正确处理 MongoDB 错误
事务管理 :复杂操作使用事务
- 适用场景
内容管理系统 :文章、评论、标签
物联网应用 :设备数据、传感器读数
实时分析 :日志分析、用户行为
电商平台 :商品目录、订单管理
社交网络 :用户资料、关系网络
MongoDB 的灵活性和高性能使其成为现代应用开发的理想选择,特别适合处理非结构化数据和需要快速迭代的项目。
通关密语:mongo