MongoDB客房预订系统Schema设计及指定日期范围可用酒店房间查询咨询
一、Schema优化建议
booking.js调整
- 新增
status字段标记预订状态,过滤掉已取消、已完成的无效订单,避免误判房间占用情况 - 新增
room+start+end+status联合索引,大幅提升日期范围查询性能 - 优化后代码:
const bookingSchema = new mongoose.Schema({ room: { type: mongoose.Schema.Types.ObjectId, ref: 'rooms', required: true }, start: { type: Date, required: true }, end: { type: Date, required: true }, // 新增状态字段,枚举值可按需扩展 status: { type: String, enum: ['confirmed', 'cancelled', 'completed'], default: 'confirmed', required: true } }); // 加联合索引,日期查询直接走索引提升效率 bookingSchema.index({ room: 1, start: 1, end: 1, status: 1 });- 新增
rooms.js调整
- 修正
hotel字段的ref取值,必须和hotel集合导出的Model名完全一致,避免populate关联失败 - 给
hotel字段加索引,方便后续按酒店分组聚合数据 - 优化后核心代码:
const roomSchema = new mongoose.Schema({ roomid: { type: String, required: true, unique: true // 房间号全局唯一约束 }, hotel: { type: mongoose.Schema.Types.ObjectId, ref: 'HotelManagers', // 和你导出的hotel集合Model名保持一致 required: true }, // 其余字段保持原有定义不变 }); roomSchema.index({ hotel: 1 });- 修正
hotels.js调整
- 密码字段必须存储哈希值禁止存明文,保障账号安全
- 可新增独立的
hotelId字段区分管理员账号和酒店实体,后续扩展同酒店多管理员场景更便捷
二、查询需求实现方案
判断房间被占用的核心逻辑:已有有效预订的时间范围和用户查询的[checkIn, checkOut]存在重叠,即满足已有预订.start < checkOut AND 已有预订.end > checkIn。
以下提供两种实现方案,初学者建议先使用更易理解调试的分步方案。
方案1:分步查询(易理解,适合中小数据量)
// 1. 先校验传入参数合法性 const checkIn = new Date(req.body.checkIn); const checkOut = new Date(req.body.checkOut); if (checkOut <= checkIn) return res.status(400).json({ msg: '离店日期必须晚于入住日期' }); // 2. 查询目标时段内所有被占用的房间ID,去重后得到数组 const occupiedRoomIds = await Booking.find({ status: 'confirmed', start: { $lt: checkOut }, end: { $gt: checkIn } }).distinct('room'); // 3. 查询所有未被占用的房间,同时关联返回酒店信息,过滤掉敏感字段 const availableRooms = await Room.find({ _id: { $nin: occupiedRoomIds } // 排除被占用的房间 }).populate('hotel', 'hotelname location img'); // 只返回需要的酒店字段,不返回密码、账号等敏感信息 // 4. 按酒店分组,整理成「酒店+对应可用客房」的返回格式 const hotelMap = {}; availableRooms.forEach(room => { const hotelId = room.hotel._id.toString(); if (!hotelMap[hotelId]) { hotelMap[hotelId] = { hotelInfo: room.hotel, availableRooms: [] }; } hotelMap[hotelId].availableRooms.push(room); }); // 最终返回结果 const result = Object.values(hotelMap); res.json(result);
方案2:聚合查询(性能更高,适合大数据量)
单条聚合语句直接完成所有逻辑,减少数据库交互次数:
const checkIn = new Date(req.body.checkIn); const checkOut = new Date(req.body.checkOut); if (checkOut <= checkIn) return res.status(400).json({ msg: '离店日期必须晚于入住日期' }); const result = await Room.aggregate([ // 关联预订表,查询每个房间在目标时段的有效预订 { $lookup: { from: 'bookings', // 替换为你booking集合的实际表名 let: { roomId: '$_id' }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ['$room', '$$roomId'] }, { $eq: ['$status', 'confirmed'] }, { $lt: ['$start', checkOut] }, { $gt: ['$end', checkIn] } ] } } } ], as: 'matchedBookings' } }, // 过滤出没有匹配预订的可用房间 { $match: { matchedBookings: { $size: 0 } } }, // 关联酒店信息 { $lookup: { from: 'hotelmanagers', // 替换为你hotel集合的实际表名 localField: 'hotel', foreignField: '_id', as: 'hotelInfo' } }, { $unwind: '$hotelInfo' }, // 按酒店分组,聚合对应所有可用房间 { $group: { _id: '$hotelInfo._id', hotelInfo: { $first: '$hotelInfo' }, availableRooms: { $push: '$$ROOT' } } }, // 移除敏感字段 { $project: { 'hotelInfo.password': 0, 'hotelInfo.username': 0, 'hotelInfo.role': 0, 'availableRooms.matchedBookings': 0 } } ]); res.json(result);
内容的提问来源于stack exchange,提问作者f4him
相关产品推荐
相关产品推荐

