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

MongoDB聚合优化:如何避免$unwind和$group实现马术酒店可用房查询

MongoDB马术酒店集合查询优化方案

你的原有实现逻辑是可行的,但确实存在冗余:两次遍历预订数组做冲突判断+$unwind拆分数组再$group合并的操作会拉高性能开销,数据量较大时查询效率会很低。可以优化为3个阶段完成查询,无需拆分酒店文档,全程在数组内完成计算,逻辑更简洁性能也更好:

优化后聚合管道

const CHECK_IN = ISODate("2021-10-23");
const CHECK_OUT = ISODate("2021-10-24");
const REQUIRED_SPOTS = 2;

[
  // 阶段1:提前过滤不符合基础条件的酒店,缩小后续计算的数据集
  {
    $match: {
      status: "approved",
      active: true
    }
  },
  // 阶段2:计算所有房间的剩余可订名额,过滤掉无可用名额的房间
  {
    $addFields: {
      availableRooms: {
        $filter: {
          input: {
            $map: {
              input: "$rooms",
              as: "room",
              in: {
                // 保留房间原有字段
                $mergeObjects: [
                  "$$room",
                  {
                    // 计算目标日期已预订的名额
                    reservedSpots: {
                      $reduce: {
                        input: { $ifNull: ["$$room.reservations", []] },
                        initialValue: 0,
                        in: {
                          $add: [
                            "$$value",
                            {
                              $cond: [
                                // 预订时间和目标入住时间冲突则计入已预订
                                {
                                  $and: [
                                    { $lt: ["$$this.fromDate", CHECK_OUT] },
                                    { $gt: ["$$this.toDate", CHECK_IN] }
                                  ]
                                },
                                "$$this.spots",
                                0
                              ]
                            }
                          ]
                        }
                      }
                    }
                  }
                ]
              }
            }
          },
          as: "room",
          // 过滤出剩余名额>0的房间
          cond: { $gt: [ { $subtract: ["$$room.spots", "$$room.reservedSpots"] }, 0 ] }
        }
      }
    }
  },
  // 阶段3:统计酒店总剩余名额,过滤出符合要求的酒店
  {
    $match: {
      $expr: {
        $gte: [
          {
            $sum: {
              $map: {
                input: "$availableRooms",
                in: { $subtract: ["$$this.spots", "$$this.reservedSpots"] }
              }
            }
          },
          REQUIRED_SPOTS
        ]
      }
    }
  }
]

优化点说明

  1. 时间冲突判断逻辑更严谨:原逻辑只判断了预订开始日期在入住区间内,优化后的判断覆盖了所有时间冲突场景:只要预订的入住区间和目标区间有重叠就算冲突,避免出现跨日预订漏判的问题。
  2. 去掉了$unwind和$group的拆分合并操作,全程在数组内完成计算,文档数不会膨胀,性能提升明显。
  3. 只用了一次$reduce遍历预订数组就完成了已预订名额计算,没有重复遍历的冗余操作。
  4. 保留了所有可用房间的完整信息,无需后续重组字段,返回结果可以直接使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 06:06:03