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

MongoDB聚合:按日期分组并按时间间隔拆分会话

MongoDB数组拆分与字段添加解决方案

针对你提出的需求,我们可以通过MongoDB的聚合管道分步实现,核心是先给数组元素标记分组,再拆分重组,最后添加目标字段:

完整聚合管道

[
  // 步骤1:给数组元素计算与下一个元素的时间差
  {
    $set: {
      visitedWithDiff: {
        $map: {
          input: { $range: [0, { $size: "$allVisitedPages" }] },
          as: "idx",
          in: {
            $mergeObjects: [
              { $arrayElemAt: ["$allVisitedPages", "$$idx"] },
              {
                timeDiffMinutes: {
                  $cond: {
                    if: { $lt: [{ $add: ["$$idx", 1] }, { $size: "$allVisitedPages" }] },
                    then: { $datediff: { startDate: { $arrayElemAt: ["$allVisitedPages.visitTime", "$$idx"] }, endDate: { $arrayElemAt: ["$allVisitedPages.visitTime", { $add: ["$$idx", 1] }] }, unit: "minute" } },
                    else: null
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  // 步骤2:给元素标记分组ID(相邻时间差>120分钟则切换分组)
  {
    $set: {
      visitedWithGroup: {
        $reduce: {
          input: "$visitedWithDiff",
          initialValue: { currentGroup: 0, items: [] },
          in: {
            currentGroup: {
              $cond: {
                if: { $and: ["$$this.timeDiffMinutes", { $gt: ["$$this.timeDiffMinutes", 120] }] },
                then: { $add: ["$$value.currentGroup", 1] },
                else: "$$value.currentGroup"
              }
            },
            items: {
              $concatArrays: [
                "$$value.items",
                [{ $mergeObjects: ["$$this", { groupId: "$$value.currentGroup" }] }]
              ]
            }
          }
        }
      }
    }
  },
  // 步骤3:拆分数组并按分组重组为新文档
  { $unwind: "$visitedWithGroup.items" },
  {
    $group: {
      _id: {
        ip: "$_id.ip",
        date: "$_id.date",
        groupId: "$visitedWithGroup.items.groupId"
      },
      allVisitedPages: { $push: "$visitedWithGroup.items" }
    }
  },
  // 步骤4:给每个元素添加durationInMinutes字段
  {
    $set: {
      allVisitedPages: {
        $map: {
          input: { $range: [0, { $size: "$allVisitedPages" }] },
          as: "idx",
          in: {
            $mergeObjects: [
              { $arrayElemAt: ["$allVisitedPages", "$$idx"] },
              {
                durationInMinutes: {
                  $cond: {
                    if: { $eq: ["$$idx", { $subtract: [{ $size: "$allVisitedPages" }, 1] }] },
                    then: 2,
                    else: { $arrayElemAt: ["$allVisitedPages.timeDiffMinutes", "$$idx"] }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  // 步骤5:清理冗余字段,保留需要的内容
  {
    $project: {
      _id: 0,
      ip: "$_id.ip",
      date: "$_id.date",
      allVisitedPages: {
        $map: {
          input: "$allVisitedPages",
          in: {
            visitTime: "$$this.visitTime",
            pageUrl: "$$this.pageUrl",
            // 这里替换成你需要保留的其他原始字段
            durationInMinutes: "$$this.durationInMinutes"
          }
        }
      }
    }
  }
]

关键逻辑说明

  • 时间差计算:用$map遍历数组,通过$datediff计算当前元素与下一个元素的分钟级时间差,最后一个元素设为null
  • 分组标记:用$reduce累计分组ID,当相邻时间差超过120分钟时,分组ID自增,确保同一连续会话的元素归属同一分组
  • 拆分重组:通过$unwind打散数组,再$group按IP、日期和分组ID重新聚合,得到拆分后的独立会话文档
  • 字段添加:再次遍历数组,给最后一个元素固定设置durationInMinutes:2,其他元素直接使用之前计算的时间差

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:20:30