如何通过MongoOperations单次数据库请求获取多分组列表?
当然可以!用MongoDB聚合框架实现单次请求分组查询
你当前的代码通过多次数据库查询来获取每个车型的前5条请求,确实可以通过MongoDB聚合框架配合MongoOperations改成单次数据库请求完成,这样能显著减少数据库交互次数,提升接口性能。
核心思路
利用聚合管道的以下阶段组合实现需求:
$match:先过滤出unlock: true的有效请求,同时可以指定需要的车型(如果不需要全量车型的话)$sort:如果你的“last five”指的是最新的5条记录,需要先按时间字段(比如createTime)倒序排序,确保取到最新数据(你当前的代码没做排序,这可能是个小隐患哦)$project:只保留业务需要的字段(对应你原来的query.fields().include()逻辑)$group:按vehicleTypeEnum分组,将每个组的文档存入数组,再用$slice截取前5条$project:将结果整理成更符合你当前Map<String, List<Request>>格式的结构
具体代码实现
下面是完整的改造示例:
public ResponseEntity<?> getFiveLastRequestOfEachVehicleType() { ResponseContent content = getResponseContent(); // 1. 构建聚合管道 Aggregation aggregation = Aggregation.newAggregation( // 筛选unlock=true的记录,同时指定需要的车型 Aggregation.match(Criteria.where("unlock").is(true) .and("vehicleTypeEnum").in(VehicleTypeEnum.NEISAN, VehicleTypeEnum.BADSAN, VehicleTypeEnum.BUJE)), // 按时间倒序(假设你有createTime字段,根据实际字段调整),确保取最新的5条 Aggregation.sort(Sort.Direction.DESC, "createTime"), // 只保留需要的字段 Aggregation.project("id", "goodsTypeTitle", "originCityTitle", "price") .and("vehicleTypeEnum").previousOperation(), // 按车型分组,截取每个组的前5条记录 Aggregation.group("vehicleTypeEnum") .push(Aggregation.ROOT).as("requests") .slice("requests", 5), // 将结果转换为方便转Map的格式 Aggregation.project("requests") .and("_id").as("vehicleType") ); // 2. 执行聚合查询 AggregationResults<VehicleTypeRequestGroup> results = mongoOperations.aggregate( aggregation, "request", // 你的集合名称,对应Request.class的映射集合 VehicleTypeRequestGroup.class ); // 3. 将结果转换为你需要的Map<String, List<Request>>格式 Map<String, List<Request>> map = results.getMappedResults().stream() .collect(Collectors.toMap( group -> group.getVehicleType().name(), VehicleTypeRequestGroup::getRequests )); content.setData(map); return getReturn(content); } // 用于接收聚合结果的DTO类 static class VehicleTypeRequestGroup { private VehicleTypeEnum vehicleType; private List<Request> requests; // Getters and Setters public VehicleTypeEnum getVehicleType() { return vehicleType; } public void setVehicleType(VehicleTypeEnum vehicleType) { this.vehicleType = vehicleType; } public List<Request> getRequests() { return requests; } public void setRequests(List<Request> requests) { this.requests = requests; } }
关键细节说明
- 排序的重要性:如果你需要的是“最近的5条”,一定要加上
$sort阶段,否则MongoDB返回的前5条是无序的,可能不符合预期。 - 字段投影:
$project阶段严格控制返回字段,和你原来的query.fields().include()逻辑保持一致,避免不必要的数据传输。 - 分组截取:
$group阶段用$push收集文档,再通过$slice直接截取前5条,替代原来的多次limit(5)查询。
对比原代码的优势
- 从3次数据库请求减少到1次,降低了网络开销和数据库连接压力
- 聚合逻辑在数据库端执行,效率更高,尤其当数据量较大时优势明显
- 代码结构更简洁,避免重复的Query构建逻辑
内容的提问来源于stack exchange,提问作者Mohsen
相关产品推荐
相关产品推荐

