You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB客房预订系统Schema设计及指定日期范围可用酒店房间查询咨询

一、Schema优化建议

  • booking.js调整

    1. 新增status字段标记预订状态,过滤掉已取消、已完成的无效订单,避免误判房间占用情况
    2. 新增room+start+end+status联合索引,大幅提升日期范围查询性能
    3. 优化后代码:
    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调整

    1. 修正hotel字段的ref取值,必须和hotel集合导出的Model名完全一致,避免populate关联失败
    2. 给hotel字段加索引,方便后续按酒店分组聚合数据
    3. 优化后核心代码:
    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调整

    1. 密码字段必须存储哈希值禁止存明文,保障账号安全
    2. 可新增独立的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 05:15:02