Node.js+MongoDB停车数据查询问题:无法匹配指定日期时段结果
停车查询筛选失效问题分析与修复
问题场景
我通过Postman发送以下请求,期望从MongoDB数据库中仅获取匹配条件的停车数据:
{ "city":"Bowie", "startTime": "2022-07-20 10:00", "duration":{ "days":"0", "hours":"3", "minutes":10 } }
2022年7月20日是周三,应该仅返回当天的停车可用时段,但实际返回了所有时段的完整数据:
{ "merchantId": { "$oid": "62c950dfc96c2b690028be88" }, "contactInfo": { "name": "Claudia Shields", "phoneNumber": 8904672101 }, "location": { "address": "737 applegate court", "city": "bowie", "state": "rhode island", "country": "greece", "zipCode": 10825 }, "price": 16, "parkingType": "residence", "parkingInfo": [ { "parkingName": "Fountain Avenue", "_id": { "$oid": "62d12053cb03235286511d55" }, "default": [] } ], "totalSpots": [ 127 ], "coordinates": { "lng": 34.048954, "lat": 10.299556 }, "status": "active", "isFeePaid": false, "parkingZone": [], "availability": [ { "day": "Saturday", "startTime": "09:00", "endTime": "14:00", "_id": { "$oid": "62d13355bd1ad85d85ae4b4b" } }, { "day": "Monday", "startTime": "08:00", "endTime": "16:00", "_id": { "$oid": "62d13375bd1ad85d85ae4b4f" } }, { "day": "Tuesday", "startTime": "08:00", "endTime": "16:00", "_id": { "$oid": "62d1337cbd1ad85d85ae4b53" } }, { "day": "Wednesday", "startTime": "08:00", "endTime": "16:00", "_id": { "$oid": "62d13383bd1ad85d85ae4b57" } }, { "day": "Thursday", "startTime": "08:00", "endTime": "16:00", "_id": { "$oid": "62d13390bd1ad85d85ae4b5b" } }, { "day": "Friday", "startTime": "08:00", "endTime": "16:00", "_id": { "$oid": "62d13396bd1ad85d85ae4b5f" } } ] }
问题原因排查
原代码存在多个逻辑错误,导致筛选完全失效:
1. 筛选逻辑未生效
查询接口中,使用parkings.filter()但未将筛选结果赋值给变量,且直接返回了原始的parkings数组,等于完全没做筛选:
exports.getParkingListByCriteria = async (req, res) => { try { endTime = getEndTime(req.body.startTime, req.body.duration); console.log(`endTime: ${endTime}`); let parkings = await Parking.find({ "location.city": req.body.city, }); const parkingList = []; // filter结果未保存,且isParkingAvailable无返回值,筛选无效 parkings.filter((parking) => { isParkingAvailable(parking.availability, req.body.startTime, endTime); }); // 直接返回原始数据 res.status(200).send(parkings); } catch (error) { return res.status(500).json({ error: error.message }); } };
2. isParkingAvailable函数核心错误
- 星期格式不匹配:
startDay是数字3(dayjs中周三对应3),但数据库中存储的是字符串"Wednesday",直接比较startDay == availabilityObject.day永远为false - 结束时间逻辑颠倒:
availabilityObject.startTime >= endTimeOnly && availabilityObject.endTime <= endTimeOnly的判断逻辑完全错误,只有当可用时段完全被结束时间点包含时才会返回true,不符合需求 - 无返回值:函数没有返回布尔值,导致filter无法获取判断结果
- 变量未声明:
startTimeOnly和endTimeOnly未用let/const声明,属于全局变量
exports.isParkingAvailable = (availability, startTime, endTime) => { let startDay = dayjs(startTime).day(); console.log(`startDay -> ${startDay}`); let endDay = dayjs(endTime).day(); console.log(`endDay -> ${endDay}`); let isStartAvailable = false; let isEndAvailable = false; // 未声明局部变量 startTimeOnly = dayjs(startTime).format("HH:mm"); console.log(`startTimeOnly -> ${startTimeOnly}`); endTimeOnly = dayjs(endTime).format("HH:mm"); console.log(`endTimeOnly -> ${endTimeOnly}`); availability.forEach((availabilityObject) => { // 数字与字符串直接比较,永远不相等 if (startDay == availabilityObject.day) { if ( availabilityObject.startTime <= startTimeOnly && availabilityObject.endTime >= startTimeOnly, console.log("availabilityObject.startTime ->",availabilityObject.startTime) ) { isStartAvailable = true; } } // 结束时间判断逻辑完全颠倒 if (endDay == availabilityObject.day) { if ( availabilityObject.startTime >= endTimeOnly && availabilityObject.endTime <= endTimeOnly ) { isEndAvailable = true; } } }); // 无返回值 };
3. 日志验证
isParkingAvailable打印的日志显示:
startDay -> 3 endDay -> 3 startTimeOnly -> 10:00 endTimeOnly -> 13:10
但数据库中availability的day字段是英文名称,导致数字与字符串无法匹配,筛选条件永远不触发。
修复方案
1. 修复isParkingAvailable函数
- 建立星期数字与英文名称的映射关系
- 修正结束时间判断逻辑
- 添加布尔值返回
- 声明局部变量
exports.isParkingAvailable = (availability, startTime, endTime) => { // dayjs星期映射:0=周日,1=周一,2=周二,3=周三,4=周四,5=周五,6=周六 const dayMap = { 0: 'Sunday', 1: 'Monday', 2: 'Tuesday', 3: 'Wednesday', 4: 'Thursday', 5: 'Friday', 6: 'Saturday' }; const startDayName = dayMap[dayjs(startTime).day()]; const endDayName = dayMap[dayjs(endTime).day()]; const startTimeOnly = dayjs(startTime).format("HH:mm"); const endTimeOnly = dayjs(endTime).format("HH:mm"); let isAvailable = false; // 遍历可用时段,判断请求时间段是否完全包含在可用时段内 for (const avail of availability) { // 同一天的情况(跨天逻辑可按需扩展) if (startDayName === avail.day && endDayName === avail.day) { if (avail.startTime <= startTimeOnly && avail.endTime >= endTimeOnly) { isAvailable = true; break; } } } return isAvailable; };
2. 修复查询接口的筛选逻辑
- 保存filter结果,返回筛选后的数组
- 可选:进一步过滤停车记录中的
availability,只保留当天的时段
exports.getParkingListByCriteria = async (req, res) => { try { const endTime = getEndTime(req.body.startTime, req.body.duration); console.log(`endTime: ${endTime}`); let parkings = await Parking.find({ // 不区分大小写匹配城市,避免大小写问题 "location.city": { $regex: new RegExp(req.body.city, 'i') } }); // 使用filter筛选符合条件的停车记录 const filteredParkings = parkings.filter((parking) => { return exports.isParkingAvailable(parking.availability, req.body.startTime, endTime); }); // 可选:只保留当天的可用时段,而非全部时段 const parkingList = filteredParkings.map(parking => { const dayMap = { 0: 'Sunday', 1: 'Monday', 2: 'Tuesday', 3: 'Wednesday', 4: 'Thursday', 5: 'Friday', 6: 'Saturday' }; const targetDay = dayMap[dayjs(req.body.startTime).day()]; const filteredAvailability = parking.availability.filter(avail => avail.day === targetDay); // 转换为普通对象后修改属性 return { ...parking.toObject(), availability: filteredAvailability }; }); res.status(200).send(parkingList); } catch (error) { return res.status(500).json({ error: error.message }); } };
额外优化建议
- 数据库中可同时存储星期数字和名称,避免每次查询都做映射
- 对城市查询添加不区分大小写匹配,避免因大小写差异导致的查询遗漏
内容的提问来源于stack exchange,提问作者Talc
相关产品推荐
相关产品推荐

