ASP.NET 6.0+MongoDB:按RateKey获取最新符合条件的酒店结果
解决方案
要实现每个符合条件的RateKey只返回最新(CreatedAt最晚)的记录,你需要使用MongoDB的聚合管道来分组并筛选每组的最新文档。以下是修改后的代码:
修改后的查询代码
public async Task<List<HotelResultDocument>> GetHotelResults(List<string> rateKeys) { var filter = Builders<HotelResultDocument>.Filter.In(x => x.RateKey, rateKeys); filter &= Builders<HotelResultDocument>.Filter.Eq(x => x.RateType, "BOOKABLE"); filter &= Builders<HotelResultDocument>.Filter.Gt(x => x.ExpiredAt, DateTime.Now); return await _hotelResultsCollection.Aggregate() .Match(filter) // 过滤符合条件的文档 .SortByDescending(doc => doc.CreatedAt) // 按CreatedAt降序排序,确保最新文档排在每组最前 .Group( key => key.RateKey, // 按RateKey分组 group => new { LatestHotel = group.First() } // 取每组第一个文档(即最新记录) ) .ReplaceRoot(result => result.LatestHotel) // 转换回原始文档结构 .ToListAsync(); }
代码说明
- Match阶段:保留原有过滤逻辑,筛选出RateKey在指定列表、RateType为"BOOKABLE"且未过期的文档。
- Sort阶段:对筛选后的文档按
CreatedAt降序排序,让每个RateKey对应的最新文档排在该组首位。 - Group阶段:以
RateKey为分组键,通过group.First()获取每组的第一个文档(也就是最新的那条记录)。 - ReplaceRoot阶段:将分组结果转换回
HotelResultDocument类型,保证返回结构与原方法一致。
优化建议
为提升查询性能,建议创建复合索引:
db.HotelResultDocuments.createIndex({ RateKey: 1, RateType: 1, ExpiredAt: 1, CreatedAt: -1 })
该索引可加速Match和Sort阶段的执行,减少数据库查询耗时。
注意事项
- 若
ExpiredAt字段存储UTC时间,建议使用DateTime.UtcNow替代DateTime.Now,避免时区差异导致的过滤错误。 - 若某个RateKey无符合条件的文档,不会出现在返回结果中。
内容的提问来源于stack exchange,提问作者hanushi-thana
相关产品推荐
相关产品推荐

