Go操作MongoDB:如何在$or查询中实现特定匹配场景的条数限制
Go操作MongoDB实现单对端ID最多返回5条记录的方案
该逻辑可直接在MongoDB侧通过聚合管道实现,无需拉取全量数据到应用层过滤,性能可控。
实现思路
整体通过聚合管道分阶段处理数据:
- 第一阶段先复用原有过滤规则,提前筛出符合基础条件的记录,缩小后续计算范围
- 第二阶段为每条命中记录计算对应的对端参与方ID:如果当前传入ID匹配partnerA,对端就是partnerB.id;如果匹配partnerB,对端就是partnerA.id
- 第三阶段通过窗口函数按对端ID分区,按业务指定的排序规则(如创建时间倒序、记录ID倒序)为每个分区内的记录生成顺序编号
- 第四阶段过滤掉分区内编号大于5的记录,实现单个对端最多返回5条的限制
- 第五阶段清理计算过程中生成的临时字段,返回和普通查询结构一致的原始文档
代码实现(基于官方mongo-go-driver)
// currentID 为接口传入的待匹配参与方ID currentID := "your_input_id" pipeline := mongo.Pipeline{ // 阶段1:基础条件匹配,完全复用原有过滤逻辑 {{"$match", bson.D{ {"unlocked", false}, {"deletedAt", nil}, {"$or", bson.A{ bson.D{ {"partnerA.id", currentID}, {"partnerA.looksInteresting", false}, }, bson.D{ {"partnerB.id", currentID}, {"partnerB.looksInteresting", false}, }, }}, }}}, // 阶段2:计算每条记录对应的对端ID {{"$addFields", bson.D{ {"counterpartyId", bson.D{ {"$cond", bson.D{ {"if", bson.D{{"$eq", bson.A{"$partnerA.id", currentID}}}}, {"then", "$partnerB.id"}, {"else", "$partnerA.id"}, }}, }}, }}}, // 阶段3:按对端ID分区,生成组内序号,排序规则可根据业务调整,示例用_id倒序 {{"$setWindowFields", bson.D{ {"partitionBy", "$counterpartyId"}, {"sortBy", bson.D{{"_id", -1}}}, {"output", bson.D{ {"recordRank", bson.D{ {"$documentNumber", bson.D{}}, }}, }}, }}}, // 阶段4:每个对端ID仅保留前5条记录 {{"$match", bson.D{ {"recordRank", bson.D{{"$lte", 5}}}, }}}, // 阶段5:移除临时字段,返回原始文档结构 {{"$unset", bson.A{"counterpartyId", "recordRank"}}}, } // 执行聚合查询 cursor, err := yourCollection.Aggregate(ctx, pipeline) if err != nil { // 自行处理错误 } // 后续解析cursor的逻辑和普通find查询一致
版本兼容提示:上述用到的
$setWindowFields窗口函数要求MongoDB版本 >= 5.0。如果使用的是更早的版本,可以替换为$group按对端ID分组+$slice取每组前5条+$unwind还原结构的方案,逻辑等价但性能略低于窗口函数实现。
内容的提问来源于stack exchange,提问作者Marius
相关产品推荐
相关产品推荐

