如何用Node.js、Mongoose、MongoDB高效获取排除司机已拒的订单数据
解决方案:MongoDB端过滤司机已拒绝的订单
不用把全量数据拉到前端处理,直接在MongoDB层面完成过滤,能大幅提升性能,下面是两种实用方案:
方案一:分步查询(简单高效)
先查询当前司机已拒绝的所有订单ID,再用这些ID排除对应订单:
// 1. 获取当前司机拒绝的订单ID列表 const declinedOrderIds = await db.driverResponse.find( { userId: "当前司机的userId", response: "DECLINED" }, { orderId: 1, _id: 0 } // 只返回orderId字段,减少数据传输 ).map(doc => doc.orderId).toArray(); // 2. 查询可用订单,排除已拒绝的 const availableOrders = await db.orders.find( { _Id: { $nin: declinedOrderIds } } ).toArray();
优化建议
给driverResponse集合创建复合索引,加速第一步查询:
db.driverResponse.createIndex({ userId: 1, response: 1, orderId: 1 })
这个索引能快速定位到指定司机的拒绝记录,避免全表扫描。
方案二:聚合管道(单查询完成)
用MongoDB的聚合管道一次性完成关联和过滤,适合需要复杂逻辑的场景:
const availableOrders = await db.orders.aggregate([ // 关联driverResponse集合,获取当前订单的所有司机响应 { $lookup: { from: "driverResponse", localField: "_Id", foreignField: "orderId", as: "driverResponses" } }, // 过滤出当前司机未拒绝的订单 { $match: { $or: [ // 情况1:没有任何司机处理过的订单 { driverResponses: { $size: 0 } }, // 情况2:当前司机没有拒绝过该订单 { "driverResponses": { $not: { $elemMatch: { userId: "当前司机的userId", response: "DECLINED" } } } } ] } }, // 可选:移除关联的driverResponses字段,只保留订单核心数据 { $project: { driverResponses: 0 } } ]).toArray();
优化建议
除了上述driverResponse的复合索引,还可以给orders的_Id字段确保有索引(默认自带),提升$lookup的关联效率。
方案对比
- 分步查询:代码简洁,调试方便,数据量不大时性能最优,还可以短时间缓存
declinedOrderIds减少重复查询。 - 聚合管道:一次查询完成,适合需要同时处理多条件过滤的场景,但数据量较大时,性能可能略逊于分步查询(因为要全量关联两个集合)。
内容的提问来源于stack exchange,提问作者Abdallah Abdelwahed
相关产品推荐
相关产品推荐

