如何将MongoDB聚合查询转为BSON并在Golang中执行及结果排查
问题排查与修复方案
核心问题分析
对比手动查询和代码生成的查询,结合Golang实现细节,三个关键问题导致返回空数据:
1. 空date条件错误过滤数据
当未传入DateFrom和DateTo时,代码将date初始化为空bson.M{}并加入$match条件。MongoDB会把{"date": {}}解析为匹配date字段值为空对象的文档,而非忽略该条件,直接过滤掉所有不符合此规则的文档,导致无结果返回。
2. mid类型不匹配
手动查询中mid的查询值是字符串"81",但代码通过convertToInt将输入字符串转为整数81。如果MongoDB集合中mid字段存储的是字符串类型,整数无法匹配字符串值,自然查不到数据。
3. Aggregate方法参数构造错误
代码调用Aggregate时使用mongo.Pipeline(primary_collection, group_collection),但mongo.Pipeline本质是[]bson.M类型,直接传入两个独立的bson.M会导致Pipeline结构异常,无法正确执行聚合逻辑。
修复后的代码
调整后的GetApnDataFromMongo函数
func GetApnDataFromMongo(data utils.Data, clientName string) (utils.Results, error) { result := utils.Results{} // 初始化match条件,仅添加有效字段 matchCond := bson.M{} // 保留mid的字符串类型,避免类型不匹配(若mid实际为整数,可恢复convertToInt) if len(data.MessageId) > 0 { matchCond["mid"] = bson.M{"$in": data.MessageId} } // 仅当DateFrom和DateTo都存在时,才添加日期过滤条件 if data.DateFrom != "" && data.DateTo != "" { matchCond["date"] = bson.M{"$gte": data.DateFrom, "$lte": data.DateTo} } primary_collection := bson.M{"$match": matchCond} group_collection := bson.M{"$group": bson.M{ "_id": "$mid", "published": bson.M{"$sum": "$published"}, "sent": bson.M{"$sum": "$sent"}, "failed": bson.M{"$sum": "$failed"}, "freqDrop": bson.M{"$sum": "$freqDrop"}, "delivered": bson.M{"$sum": "$delivered"}, "clicked": bson.M{"$sum": "$open"}, }} // 正确构造Pipeline fullquery := mongo.Pipeline{primary_collection, group_collection} jsonString, _ := json.Marshal(fullquery) logrus.Info(fmt.Sprintf("Final query prepared is as following %+v", string(jsonString))) ctx := context.Background() conn, err := utils.GetMongoConnection() if err != nil { logrus.Errorf("Error connecting to mongo %+v", err) return result, err } logrus.Info("clientName %+v", clientName) // 使用正确的Pipeline参数执行聚合 resultData, err := conn.Database(clientName).Collection("apnSummary").Aggregate(ctx, fullquery) if err != nil { logrus.Errorf("Error querying %+v", err) return result, err } mongodata := []utils.MonogResponse{} // 新增解码错误检查,避免忽略异常 if err := resultData.All(ctx, &mongodata); err != nil { logrus.Errorf("Error decoding data %+v", err) return result, err } fmt.Println(mongodata) result = PrepareMongoResponse(mongodata) return result, nil }
额外优化点
- 移除了
convertToInt函数,直接使用传入的字符串MessageId,确保与MongoDB中mid字段类型一致(若mid实际为整数类型,可恢复转换逻辑)。 - 添加了
resultData.All方法的错误检查,避免忽略数据解码过程中的异常。
内容的提问来源于stack exchange,提问作者Sri Chak
相关产品推荐
相关产品推荐

