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

Mongoose复杂查询构建:筛选指定时段可用的Pro

如何用Mongoose筛选符合时段要求且非不可用的Pro?

我来帮你完善这个查询,咱们一步步拆解剩下的需求:匹配指定时段的可用时间、排除不可用时段,还要过滤掉状态不可用的Pro。

第一步:先把请求的时间转换成便于对比的格式

首先,我们需要把请求的date_start转换成当天的总分钟数,同时计算出时段结束的总分钟数,这样就能和availability里的h、m直接对比了:

const date_start = new Date(req.body.date_start);
const duration = req.body.duration; // 单位是小时
const date_finish = new Date(date_start.getTime() + (1000 * 60 * 60 * duration));

// 计算当天的起始分钟数(比如12:30就是12*60+30=750)
const startHour = date_start.getHours();
const startMinute = date_start.getMinutes();
const startTotalMin = startHour * 60 + startMinute;

// 计算时段结束的总分钟数
const endTotalMin = startTotalMin + duration * 60;

const targetDay = parseInt(date_start.getDay(), 10);

第二步:完善查询条件

我们需要在现有查询基础上,添加三个关键条件:

  1. 匹配availability的可用时段:找到对应星期几的availability条目,确保请求的时段完全落在该条目的from到to之间
  2. 排除unavailability的冲突时段:确保Pro的不可用时段和请求的时段没有重叠
  3. 排除不可用状态的Pro:过滤掉status为disabled的Pro

完整的查询代码如下:

const availablePros = await Pro.find({
  // 已有的筛选条件
  services: req.body.service_id,
  zone: req.body.zone_id,
  // 排除不可用状态
  status: { $ne: "disabled" },
  // 匹配对应星期几的可用时段,且请求时段完全在该时段内
  availability: {
    $elemMatch: {
      day: targetDay,
      $expr: {
        $and: [
          // 可用时段的起始分钟 <= 请求时段起始分钟
          { $lte: [{ $add: ["$from.h", { $multiply: ["$from.m", 1/60] }] }, startHour + startMinute/60] },
          // 可用时段的结束分钟 >= 请求时段结束分钟
          { $gte: [{ $add: ["$to.h", { $multiply: ["$to.m", 1/60] }] }, (startHour + startMinute/60) + duration] }
        ]
      }
    }
  },
  // 排除存在冲突不可用时段的Pro:没有任何一个unavailability条目和请求时段重叠
  unavailability: {
    $not: {
      $elemMatch: {
        from: { $lt: date_finish },
        to: { $gt: date_start }
      }
    }
  }
}).populate('services zone'); // 按需关联查询关联集合

关键条件解释

  • availability的$expr用法:因为我们需要把文档里的from.h、from.m转换成小时数(或者总分钟数)和请求的时间对比,用$expr可以在查询里执行算术运算,避免在代码里做额外转换。
  • unavailability的冲突判断:两个时间段重叠的逻辑是「不可用时段的开始 < 请求时段的结束,且不可用时段的结束 > 请求时段的开始」,用$not和$elemMatch就能排除所有存在这种冲突的Pro。
  • status过滤:直接排除status为disabled的Pro,如果你只有confirmed状态是可用的,也可以改成status: "confirmed"。

结合你的示例数据验证

比如你提供的Pro 3(_id: 5ae5946a8c09fc67c714597d):

  • 它的services和zone都匹配请求参数,但status是disabled,会被第一个过滤条件排除;
  • 同时它的unavailability时段和请求的date_start(假设是周日,对应day=0)也可能冲突,双重保障不会被筛选出来。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:57:10