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

Node.js中MongoDB同集合仅返回指定日期的availability元素

MongoDB查询:按需返回指定日期区间的availability数据

问题场景

我有如下MongoDB集合示例:

{"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"}}]}

通过Postman发送的请求参数:

{"city":"edmund","startTime": "2022-07-25 11:00","duration":{"days":"0","hours":"3","minutes":"00"}}

需求明确:

  • 2022年7月25日是周一,请求时长3小时(未超过24小时),仅返回周一的availability数据,过滤掉周二至周六的条目;
  • 若请求时长超过24小时,则仅返回周一和周二的availability数据。

我尝试用$elemMatch做投影,但代码仍返回所有availability条目:

exports.getParkingListByCriteria = async (req, res) => { 
  try { 
    endTime = getEndTime(req.body.startTime, req.body.duration); 
    const startTime = dayjs(req.body.startTime, "YYYY-MM-DD HH:mm").format("dddd"); 
    let parkings = await Parking.find(
      { "location.city": req.body.city}, 
      { "availability.day": { $elemMatch: { day: startTime } } } 
      // 试过这个写法,但仍返回周一到周六的所有availability,硬写"Monday"也没用
    ); 
    parkingList = []; 
    parkings.filter((parking) => { 
      if (isParkingAvailable(parking.availability, req.body.startTime, endTime)) 
        parkingList.push(parking); 
    }); 
    res.status(200).send(parkingList); 
  } catch (error) { 
    return res.status(500).json({ error: error.message }); 
  } 
};

解决方案

问题根源

你用$elemMatch的写法错误,"availability.day": { $elemMatch: ... }只会匹配数组元素里的day字段,不会过滤整个数组条目。正确做法是直接对availability数组使用过滤逻辑,同时要根据请求时长判断需要保留哪些星期几的数据。

方法一:聚合管道过滤(推荐,数据库层面处理,性能更优)

exports.getParkingListByCriteria = async (req, res) => { 
  try { 
    const { city, startTime: reqStartTime, duration } = req.body;
    const start = dayjs(reqStartTime, "YYYY-MM-DD HH:mm");
    const end = getEndTime(reqStartTime, duration);
    const endDayjs = dayjs(end);
    
    // 确定需要保留的星期几
    const requiredDays = [];
    const startDay = start.format("dddd");
    requiredDays.push(startDay);
    // 时长超过24小时则添加下一天
    if (endDayjs.diff(start, 'hour') >= 24) {
      const nextDay = start.add(1, 'day').format("dddd");
      requiredDays.push(nextDay);
    }

    // 用聚合管道完成文档匹配+数组过滤
    let parkings = await Parking.aggregate([
      // 第一步:匹配目标城市
      { $match: { "location.city": city } },
      // 第二步:过滤availability数组,只保留指定星期几的条目
      {
        $addFields: {
          availability: {
            $filter: {
              input: "$availability",
              as: "avail",
              cond: { $in: ["$$avail.day", requiredDays] }
            }
          }
        }
      },
      // 可选:过滤掉availability为空的无效文档
      { $match: { "availability.0": { $exists: true } } }
    ]);

    // 继续执行你的可用性判断逻辑
    const parkingList = parkings.filter(parking => 
      isParkingAvailable(parking.availability, reqStartTime, end)
    );

    res.status(200).send(parkingList); 
  } catch (error) { 
    return res.status(500).json({ error: error.message }); 
  } 
};

方法二:查询后在代码层过滤数组(小数据量场景适用)

如果不想用聚合,也可以在拿到数据库返回的文档后,手动过滤availability数组:

exports.getParkingListByCriteria = async (req, res) => { 
  try { 
    endTime = getEndTime(req.body.startTime, req.body.duration); 
    const start = dayjs(req.body.startTime, "YYYY-MM-DD HH:mm");
    const endDayjs = dayjs(endTime);
    
    // 确定需要保留的星期几
    const requiredDays = [start.format("dddd")];
    if (endDayjs.diff(start, 'hour') >= 24) {
      requiredDays.push(start.add(1, 'day').format("dddd"));
    }

    // 先查询匹配城市的所有文档
    let parkings = await Parking.find({ "location.city": req.body.city }); 

    // 过滤文档+处理availability数组
    const parkingList = parkings.filter(parking => {
      // 只保留需要的星期几的availability条目
      parking.availability = parking.availability.filter(avail => 
        requiredDays.includes(avail.day)
      );
      // 过滤掉无有效availability的文档,再执行可用性判断
      return parking.availability.length > 0 && isParkingAvailable(parking.availability, req.body.startTime, endTime);
    }); 

    res.status(200).send(parkingList); 
  } catch (error) { 
    return res.status(500).json({ error: error.message }); 
  } 
};

核心说明

  • $filter聚合操作符可以精准筛选数组中符合条件的元素,是数据库层面过滤数组的最优方式;
  • 用dayjs的diff方法计算时间间隔,判断是否需要包含下一天的availability数据;
  • 大数据量场景优先用聚合管道,减少数据库传输到服务端的数据量;小数据量场景用代码层过滤更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 00:48:23