MongoDB聚合与查询优化详解
1. MongoDB聚合框架
1.1 聚合管道基础
// 使用mongo-driver pipeline := mongo.Pipeline{ {{Key: "$match", Value: bson.D{{Key: "status", Value: "active"}}}}, {{Key: "$group", Value: bson.D{ {Key: "_id", Value: "$department"}, {Key: "count", Value: bson.D{{Key: "$sum", Value: 1}}}, {Key: "avgSalary", Value: bson.D{{Key: "$avg", Value: "$salary"}}}, }}}, {{Key: "$sort", Value: bson.D{{Key: "count", Value: -1}}}}, } cursor, err := collection.Aggregate(ctx, pipeline)1.2 常用聚合阶段
-- $match: 过滤文档 { $match: { status: "active", age: { $gte: 18 } } } -- $group: 分组 { $group: { _id: "$department", total: { $sum: 1 } } } -- $sort: 排序 { $sort: { total: -1 } } -- $limit: 限制数量 { $limit: 10 } -- $skip: 跳过文档 { $skip: 5 } -- $project: 选择字段 { $project: { name: 1, age: 1, _id: 0 } } -- $lookup: 左连接 { $lookup: { from: "orders", localField: "user_id", foreignField: "user_id", as: "user_orders" } }2. 聚合表达式
2.1 算术表达式
// $add, $subtract, $multiply, $divide, $mod, $pow pipeline := mongo.Pipeline{ {{Key: "$addFields", Value: bson.D{ {Key: "totalPrice", Value: bson.D{{Key: "$multiply", Value: bson.A{"$price", "$quantity"}}}}, }}}, }2.2 字符串表达式
// $concat, $toUpper, $toLower, $substr, $trim pipeline := mongo.Pipeline{ {{Key: "$addFields", Value: bson.D{ {Key: "fullName", Value: bson.D{{Key: "$concat", Value: bson.A{"$firstName", " ", "$lastName"}}}}, }}}, }2.3 条件表达式
// $cond, $ifNull, $switch pipeline := mongo.Pipeline{ {{Key: "$addFields", Value: bson.D{ {Key: "status", Value: bson.D{ {Key: "$cond", Value: bson.A{ bson.D{{Key: "$gte", Value: bson.A{"$score", 60}}}, "pass", "fail", }}, }}, }}}, }3. 查询优化
3.1 索引使用分析
// 使用explain分析查询 explain, err := collection.Find(ctx, filter).Explain(ctx) // 查看查询计划 cursor, err := collection.Find(ctx, filter, options.Find().SetHint("status_1"))3.2 覆盖索引
// 创建覆盖索引 indexModel := mongo.IndexModel{ Keys: bson.D{ {Key: "user_id", Value: 1}, {Key: "name", Value: 1}, }, Options: options.Index().SetProjection(bson.D{{Key: "_id", Value: 0}}), } collection.Indexes().CreateOne(ctx, indexModel) // 查询只使用索引 cursor, err := collection.Find(ctx, bson.D{{Key: "user_id", Value: 1}}, options.Find().SetProjection(bson.D{{Key: "name", Value: 1}})3.3 慢查询分析
// 查看慢查询 result := mongo.Database("admin").RunCommand(ctx, bson.D{{Key: "profile", Value: 2}}) // 设置慢查询阈值 mongo.Database("admin").RunCommand(ctx, bson.D{ {Key: "setParameter", Value: 1}, {Key: "slowms", Value: 100}, })4. 查询模式
4.1 分页查询
// 简单分页 skip := int64((page - 1) * pageSize) limit := int64(pageSize) cursor, err := collection.Find(ctx, filter, options.Find().SetSkip(skip).SetLimit(limit).SetSort(bson.D{{Key: "created_at", Value: -1}})) // 游标分页(适合大数据量) var lastID primitive.ObjectID cursor, err := collection.Find(ctx, bson.D{ {Key: "_id", Value: bson.D{{Key: "$gt", Value: lastID}}}, {Key: "status", Value: "active"}, })4.2 模糊查询
// 使用正则 cursor, err := collection.Find(ctx, bson.D{ {Key: "name", Value: bson.D{{Key: "$regex", Value: "john"}}}, }) // 前缀匹配(可使用索引) cursor, err := collection.Find(ctx, bson.D{ {Key: "name", Value: bson.D{{Key: "$regex", Value: "^john"}}}, })4.3 数组查询
// 查询数组包含 cursor, err := collection.Find(ctx, bson.D{ {Key: "tags", Value: "mongodb"}}, ) // 查询数组包含所有元素 cursor, err := collection.Find(ctx, bson.D{ {Key: "tags", Value: bson.D{{Key: "$all", Value: bson.A{"mongodb", "database"}}}}, }) // 按数组元素查询 cursor, err := collection.Find(ctx, bson.D{ {Key: "ratings.0.stars", Value: 5}}, )5. 索引优化
5.1 复合索引
// 创建复合索引 indexModel := mongo.IndexModel{ Keys: bson.D{ {Key: "user_id", Value: 1}, {Key: "created_at", Value: -1}, {Key: "status", Value: 1}, }, } collection.Indexes().CreateOne(ctx, indexModel)5.2 多键索引
// 对数组字段创建索引 indexModel := mongo.IndexModel{ Keys: bson.D{{Key: "tags", Value: 1}}, } collection.Indexes().CreateOne(ctx, indexModel) // 对嵌套数组创建索引 indexModel := mongo.IndexModel{ Keys: bson.D{{Key: "reviews.rating", Value: 1}}, } collection.Indexes().CreateOne(ctx, indexModel)5.3 索引管理
// 查看所有索引 indexes, err := collection.Indexes().List(ctx) // 创建索引 _, err = collection.Indexes().CreateOne(ctx, mongo.IndexModel{ Keys: bson.D{{Key: "name", Value: 1}}, Options: options.Index().SetUnique(true), }) // 删除索引 collection.Indexes().DropOne(ctx, "name_1") // 查看索引大小 var stats bson.M collection.Database().RunCommand(ctx, bson.D{ {Key: "indexStats", Value: collection.Name()}, }, &stats)6. 性能最佳实践
6.1 查询优化原则
- 使用覆盖索引避免回表
- 避免全表扫描
- 合理使用投影减少传输数据
- 使用分页处理大数据集
- 避免使用$where和$function
6.2 写入优化
// 批量写入 models := make([]mongo.WriteModel, len(docs)) for i, doc := range docs { models[i] = mongo.NewInsertOneModel().SetDocument(doc) } result, err := collection.BulkWrite(ctx, models) // 顺序写入比随机写入快6.3 连接池配置
clientOptions := options.Client(). ApplyURI("mongodb://localhost:27017"). SetMaxPoolSize(100). SetMinPoolSize(10). SetMaxConnIdleTime(30 * time.Second) client, err := mongo.Connect(ctx, clientOptions)7. 总结
MongoDB聚合框架提供了强大的数据处理能力,通过合理的管道设计可以实现复杂的查询和分析。查询优化需要关注索引设计、查询模式和写入策略,通过explain分析和慢查询监控持续改进性能。