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

MongoDB按条件查询数组内对象 查找指定时段餐厅可用桌台

问题排查与修复方案

原有代码的核心问题

  • 错误1:查询条件"tables[0].bookings"硬编码了数组下标0,仅校验第1张桌台的预订记录,不会遍历所有桌台
  • 错误2:findOne默认返回完整的门店文档,不会单独返回匹配条件的桌台对象
  • 错误3:后续操作直接修改门店文档的isBooked和bookings字段,完全没有命中对应桌台的属性,写入逻辑完全错误

最优解决方案:原子更新(避免并发超订)

推荐直接用findOneAndUpdate单查询完成「校验可用桌台+写入预订信息」的操作,全程是原子操作,不会出现多个用户同时抢到同一张桌的问题:

const mongoose = require('mongoose');
const stringDate = new Date(date).toLocaleDateString();
const placeId = req.body.placeId;
const bookingData = {
  Name: name,
  Time: time,
  Date: stringDate,
  numOfPersons: parseInt(personsNumber),
  Note: note,
  User: userId,
};

// 1. 匹配条件:指定门店,且存在至少一张桌台没有当前时段的预订记录
// 2. 更新操作:给第一张符合条件的桌台推入新的预订信息
// 3. 配置项返回更新后的文档、只返回匹配的桌台
const result = await Places.findOneAndUpdate(
  {
    _id: placeId,
    tables: {
      $elemMatch: {
        bookings: {
          $not: {
            $elemMatch: { Date: stringDate, Time: time }
          }
        }
      }
    }
  },
  {
    $push: {
      "tables.$.bookings": bookingData
    }
    // 如果isBooked是时段标记、而非桌台全局占用标记,可以加下面这行同步更新
    // $set: { "tables.$.isBooked": true }
  },
  { 
    new: true, // 返回更新后的文档
    projection: { tables: { $elemMatch: { bookings: { $not: { $elemMatch: { Date: stringDate, Time: time } } } } } 
  }
);

// 拿到最终被预订的桌台信息
const bookedTable = result.tables[0];

注意:你现有Schema里的isBooked字段设计不符合分时段预订的场景,同一张桌不同时段可以被不同用户预订,不要全局修改该字段为true,否则其他时段的用户无法正常预订该桌。

如果你需要先返回所有可用桌台给用户选择,再确认预订,可以用聚合查询先查可用桌台列表:

const availableTables = await Places.aggregate([
  // 先匹配指定门店
  { $match: { _id: mongoose.Types.ObjectId(placeId) } },
  // 拆分tables数组为单独的文档
  { $unwind: "$tables" },
  // 过滤掉当前时段已经被预订的桌台
  {
    $match: {
      "tables.bookings": {
        $not: {
          $elemMatch: { Date: stringDate, Time: time }
        }
      }
    }
  },
  // 只返回桌台信息,剔除门店其他冗余字段
  { $replaceRoot: { newRoot: "$tables" } }
]);

内容的提问来源于stack exchange,提问作者Rawand122

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 10:48:00