如何用Mongoose查询指定日期区间与MongoDB数组日期是否重叠
修复MongoDB日期重叠查询问题
原查询的核心问题是逻辑错误,只匹配了「现有预订时间段完全包含指定时间段」的场景,漏掉了其他所有重叠情况;另外还有不必要的日期格式转换可能导致类型不匹配。
日期重叠的正确判断逻辑
两个时间段存在重叠的反面是「完全不重叠」,完全不重叠的条件只有两种:
- 现有预订的结束日期 ≤ 指定的起始日期
- 现有预订的起始日期 ≥ 指定的结束日期
所以我们只需要查询不满足上述任一条件的文档,就能找到存在重叠预订的记录。
修复后的Mongoose查询代码
// 确保initDate和endingDayBufferCalcWithContractDays是Date类型,无需转成字符串 const getAvailabilityDetails = await Products.find({ _id: pid, bookings: { $elemMatch: { $nor: [ { productBookingCompleteDate: { $lte: initDate } }, { productBookingStartDate: { $gte: endingDayBufferCalcWithContractDays } } ] } } });
等价的$or写法(枚举所有重叠场景)
如果更直观的话,也可以直接枚举所有重叠的情况:
const getAvailabilityDetails = await Products.find({ _id: pid, bookings: { $elemMatch: { $or: [ // 现有预订包含指定时间段 { productBookingStartDate: { $lte: initDate }, productBookingCompleteDate: { $gte: endingDayBufferCalcWithContractDays } }, // 指定时间段包含现有预订 { productBookingStartDate: { $gte: initDate }, productBookingCompleteDate: { $lte: endingDayBufferCalcWithContractDays } }, // 现有预订开始于指定时间段内 { productBookingStartDate: { $gte: initDate, $lte: endingDayBufferCalcWithContractDays } }, // 现有预订结束于指定时间段内 { productBookingCompleteDate: { $gte: initDate, $lte: endingDayBufferCalcWithContractDays } } ] } } });
关键注意事项
- 确保
initDate和endingDayBufferCalcWithContractDays是Date对象,不要转成ISO字符串或其他格式,MongoDB会自动处理Date类型的比较 - 使用
$elemMatch确保数组中至少有一个booking满足重叠条件
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

