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

MongoDB聚合框架下按visitor_id和签到日期合并多对象实现方案咨询

MongoDB聚合管道合并同访客同日期打卡记录方案

实现思路

核心是按visitor_id + clocked_in_at的日期维度分组,利用原始数据已按clocked_in_at升序排列的特性,分组时用$first取分组内第一条的clocked_in_at和原始_id,用$last取分组内最后一条的clocked_out_at即可满足需求。

具体实现

场景1:待处理数据是独立的文档流

db.collection.aggregate([
  // 1. 提取打卡日期作为分组依据,如果clocked_in_at是字符串类型,先转ISODate:date: { $toDate: "$clocked_in_at" }
  {
    $addFields: {
      clocked_in_date: {
        $dateToString: {
          format: "%Y-%m-%d",
          date: "$clocked_in_at"
        }
      }
    }
  },
  // 2. 按访客ID+打卡日期分组
  {
    $group: {
      _id: {
        visitor_id: "$visitor_id",
        date: "$clocked_in_date"
      },
      original_id: { $first: "$_id" },
      clocked_in_at: { $first: "$clocked_in_at" },
      clocked_out_at: { $last: "$clocked_out_at" }
    }
  },
  // 3. 调整字段结构为目标格式
  {
    $project: {
      _id: "$original_id",
      visitor_id: "$_id.visitor_id",
      clocked_in_at: 1,
      clocked_out_at: 1
    }
  },
  // 可选:恢复原始打卡时间排序
  {
    $sort: { clocked_in_at: 1 }
  }
])

场景2:待处理数组是某文档的嵌套字段(假设字段名为records)

db.collection.aggregate([
  // 拆分嵌套数组
  { $unwind: "$records" },
  // 提取打卡日期
  {
    $addFields: {
      "records.clocked_in_date": {
        $dateToString: {
          format: "%Y-%m-%d",
          date: "$records.clocked_in_at"
        }
      }
    }
  },
  // 按原文档ID、访客ID、打卡日期分组
  {
    $group: {
      _id: {
        root_id: "$_id",
        visitor_id: "$records.visitor_id",
        date: "$records.clocked_in_date"
      },
      original_record_id: { $first: "$records._id" },
      clocked_in_at: { $first: "$records.clocked_in_at" },
      clocked_out_at: { $last: "$records.clocked_out_at" }
    }
  },
  // 重新组装为嵌套数组
  {
    $group: {
      _id: "$_id.root_id",
      records: {
        $push: {
          _id: "$original_record_id",
          visitor_id: "$_id.visitor_id",
          clocked_in_at: "$clocked_in_at",
          clocked_out_at: "$clocked_out_at"
        }
      }
    }
  },
  // 可选:给嵌套数组按打卡时间排序
  {
    $addFields: {
      records: {
        $sortArray: {
          input: "$records",
          sortBy: { clocked_in_at: 1 }
        }
      }
    }
  }
])

常见问题说明

之前用$mergeObjects达不到预期是因为该算子会全量合并同名字段,默认用后出现的字段值覆盖先出现的,而你需要的是指定取分组首尾的特定字段,直接在$group阶段用$first和$last取值更贴合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 20:45:08