Golang操作MongoDB:按ConfigId分组查最新记录并过滤
MongoDB 查询实现:分组取最新记录并过滤
数据结构(Go)
type History struct { ID primitive.ObjectID `bson:"_id"` ConfigId string `bson:"configId"` IsClosed bool `bson:"isClosed"` CreatedTime time.Time `bson:"createdTime"` ValidityTime time.Time `bson:"validityTime"` }
需求实现(聚合管道)
直接使用MongoDB聚合管道完成分组取最新、二次过滤的需求,以下是Go语言中的实现代码:
// 获取当前时间 now := time.Now() // 构建聚合管道 pipeline := []bson.M{ // 按创建时间倒序排序,确保每组最新记录排在前列 {"$sort": bson.M{"createdTime": -1}}, // 按ConfigId分组,取每组第一条(即创建时间最新的记录) {"$group": bson.M{ "_id": "$configId", "latestRecord": bson.M{"$first": "$$ROOT"}, // 保留整条记录结构 }}, // 将嵌套的最新记录提升为根文档,简化后续过滤 {"$replaceRoot": bson.M{"newRoot": "$latestRecord"}}, // 过滤出符合条件的记录 {"$match": bson.M{ "isClosed": true, "validityTime": bson.M{"$lt": now}, }}, } // 执行聚合查询 var results []History err := collection.Aggregate(context.TODO(), pipeline).All(&results) if err != nil { // 处理查询错误 }
关键阶段说明
- $sort:全局按
createdTime倒序排列,保证同一ConfigId下最新的记录排在最前面 - $group:按
configId分组,用$first获取每组的第一条记录,$$ROOT表示保留整条文档的所有字段 - $replaceRoot:将分组后嵌套的
latestRecord转换为根文档结构,避免后续过滤操作需要嵌套访问字段 - $match:最终筛选出
isClosed为true且validityTime早于当前时间的记录
大数据量优化方案
如果数据集规模极大,全局排序性能受限,可改用先获取每组最大创建时间、再关联原集合的方式:
now := time.Now() pipeline := []bson.M{ // 分组获取每组的最大创建时间 {"$group": bson.M{ "_id": "$configId", "maxCreatedTime": bson.M{"$max": "$createdTime"}, }}, // 关联原集合,匹配对应ConfigId和最大创建时间的记录 {"$lookup": bson.M{ "from": "history", // 替换为你的实际集合名称 "localField": "_id", "foreignField": "configId", "pipeline": []bson.M{ {"$match": bson.M{ "$expr": bson.M{"$eq": []string{"$createdTime", "$$maxCreatedTime"}}, }}, }, "as": "latestRecords", }}, // 展开关联结果数组 {"$unwind": "$latestRecords"}, // 替换为根文档 {"$replaceRoot": bson.M{"newRoot": "$latestRecords"}}, // 最终过滤 {"$match": bson.M{ "isClosed": true, "validityTime": bson.M{"$lt": now}, }}, }
内容的提问来源于stack exchange,提问作者EagerLearner
相关产品推荐
相关产品推荐

