Golang MGO多参数分组并按datetime获取最新记录
用Golang + mgo实现分组取最新测试记录
嘿,这个需求我之前做项目时刚好碰到过,用MongoDB的聚合框架搭配mgo就能完美解决!下面给你捋清楚思路和具体代码:
核心思路
我们需要通过聚合管道分三步搞定:
- 分组取最新时间:按
serial number、stage、stage order这三个字段分组,把每组里最大的datetime(也就是最新完成的记录时间)捞出来 - 关联原集合拿完整记录:把第一步的分组结果和原测试记录集合关联,匹配出对应那个最新时间的完整记录
- 整理输出字段:去掉聚合过程中生成的冗余数据,只保留你需要的字段
具体代码实现
先假设你的测试记录结构体是这样的(根据实际字段调整就行):
import ( "fmt" "time" "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" ) type TestRecord struct { SerialNumber string `bson:"serial number"` Stage string `bson:"stage"` StageOrder int `bson:"stage order"` Datetime time.Time `bson:"datetime"` // 这里加你实际的其他字段,比如测试结果、备注之类的 Result string `bson:"result"` }
然后是执行聚合查询的核心代码:
// 先建立MongoDB连接 session, err := mgo.Dial("mongodb://localhost:27017") if err != nil { panic(fmt.Errorf("连接MongoDB失败: %v", err)) } defer session.Close() // 指定你的数据库和集合 coll := session.DB("your_test_db").C("test_records") // 构建聚合管道 pipeline := []bson.M{ // 第一步:分组,获取每组的最新datetime { "$group": bson.M{ "_id": bson.M{ "serialNumber": "$serial number", "stage": "$stage", "stageOrder": "$stage order", }, "latestDatetime": bson.M{"$max": "$datetime"}, }, }, // 第二步:关联原集合,多字段匹配找到对应最新记录 // 这里用let+子管道的方式,因为要匹配多个字段的组合 { "$lookup": bson.M{ "from": "test_records", "let": bson.M{ "sn": "$_id.serialNumber", "stage": "$_id.stage", "stageOrder": "$_id.stageOrder", "latestDt": "$latestDatetime", }, "pipeline": []bson.M{ { "$match": bson.M{ "$expr": bson.M{ "$and": []bson.M{ {"$eq": ["$serial number", "$$sn"]}, {"$eq": ["$stage", "$$stage"]}, {"$eq": ["$stage order", "$$stageOrder"]}, {"$eq": ["$datetime", "$$latestDt"]}, }, }, }, }, }, "as": "latestRecord", }, }, // 展开关联后的数组(每组只会匹配到一条记录,所以放心unwind) {"$unwind": "$latestRecord"}, // 第三步:投影出需要的字段,去掉中间生成的_id等冗余数据 { "$project": bson.M{ "_id": 0, "serial number": "$latestRecord.serial number", "stage": "$latestRecord.stage", "stage order": "$latestRecord.stage order", "datetime": "$latestRecord.datetime", "result": "$latestRecord.result", // 换成你实际需要的其他字段 }, }, } // 执行聚合查询,把结果映射到TestRecord切片里 var latestRecords []TestRecord if err := coll.Pipe(pipeline).All(&latestRecords); err != nil { panic(fmt.Errorf("执行聚合查询失败: %v", err)) } // 遍历结果看看 for _, record := range latestRecords { fmt.Printf("序列号: %s, 阶段: %s, 最新测试时间: %v, 结果: %s\n", record.SerialNumber, record.Stage, record.Datetime, record.Result) }
小提醒
- 如果你的
datetime字段存的是字符串而不是MongoDB的Date类型,记得先转成Date类型再用$max,不然字符串比较会出问题(比如格式不统一时会出错) - 聚合管道里的
from字段要和你的集合名称完全一致,MongoDB是大小写敏感的哦 - 就算每组本来就只有一条记录,这个查询也能正常返回,完全兼容你的场景
内容的提问来源于stack exchange,提问作者xXPhenom22Xx
相关产品推荐
相关产品推荐

