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

MongoDB查询实现夜班考勤记录合并次日首条打卡数据

问题描述

我是MongoDB和Node.js新手,正在开发考勤系统,需求如下:

  • 当当日班次为夜班时,将次日的第一条打卡记录合并到当日的考勤记录中

当前数据结构

[
    {
        "date": "2023-04-01",
        "shift": {
            "date": "2023-04-01",
            "shiftType": {
                "isNight": true
            }
        },
        "attendances": [
            {
                "_id": "6422d1b9994726677e9105c6",
                "employee": "622061b73b2eaac4b15d42e4",
                "dateTime": "2023-04-01T05:30:00.000Z"
            }
        ]
    },
    {
        "date": "2023-04-02",
        "shift": {
            "isNight": false
        },
        "attendances": [
            {
                "_id": "6422d1b9994726677e9105c7",
                "employee": "622061b73b2eaac4b15d42e4",
                "dateTime": "2023-04-02T00:30:00.000Z"
            },
            {
                "_id": "6423286e2746f65c2480a13e",
                "employee": "622061b73b2eaac4b15d42e4",
                "dateTime": "2023-04-02T04:30:00.000Z"
            },
            {
                "_id": "6423286e2746f65c2480a13f",
                "employee": "622061b73b2eaac4b15d42e4",
                "dateTime": "2023-04-02T12:40:00.000Z"
            }
        ]
    }
]

期望数据结构

[
    {
        "date": "2023-04-01",
        "shift": {
            "date": "2023-04-01",
            "shiftType": {
                "isNight": true
            }
        },
        "attendances": [
            {
                "_id": "6422d1b9994726677e9105c6",
                "employee": "622061b73b2eaac4b15d42e4",
                "dateTime": "2023-04-01T05:30:00.000Z"
            },
            {
                "_id": "6422d1b9994726677e9105c7",
                "employee": "622061b73b2eaac4b15d42e4",
                "dateTime": "2023-04-02T00:30:00.000Z"
            }
        ]
    },
    {
        "date": "2023-04-02",
        "shift": {
            "isNight": false
        },
        "attendances": [
            {
                "_id": "6423286e2746f65c2480a13e",
                "employee": "622061b73b2eaac4b15d42e4",
                "dateTime": "2023-04-02T04:30:00.000Z"
            },
            {
                "_id": "6423286e2746f65c2480a13f",
                "employee": "622061b73b2eaac4b15d42e4",
                "dateTime": "2023-04-02T12:40:00.000Z"
            }
        ]
    }
]

请问是否可通过MongoDB查询实现该需求?望得到帮助,谢谢!


解决方案

可以通过MongoDB的聚合管道实现该需求,核心逻辑是通过自连接匹配次日记录,再根据班次类型合并或清理打卡数据,具体实现如下:

db.yourCollectionName.aggregate([
  // 1. 计算每条记录的次日日期,用于关联次日考勤数据
  {
    $addFields: {
      nextDay: {
        $dateToString: {
          format: "%Y-%m-%d",
          date: { $add: [{ $toDate: "$date" }, 86400000] } // 86400000毫秒 = 1天
        }
      }
    }
  },
  // 2. 自连接集合,获取次日对应的考勤记录
  {
    $lookup: {
      from: "yourCollectionName",
      localField: "nextDay",
      foreignField: "date",
      as: "nextDayRecord"
    }
  },
  // 3. 处理考勤数据:合并夜班当日与次日第一条打卡,清理次日记录的已合并打卡
  {
    $project: {
      date: 1,
      shift: 1,
      attendances: {
        $cond: [
          // 判断当前是否为夜班(兼容两种shift结构)
          { $or: [{ $eq: ["$shift.shiftType.isNight", true] }, { $eq: ["$shift.isNight", true] }] },
          // 夜班:合并当前考勤与次日第一条打卡
          {
            $concatArrays: [
              "$attendances",
              { $slice: [{ $arrayElemAt: ["$nextDayRecord.attendances", 0] }, 1] }
            ]
          },
          // 非夜班:如果是被夜班关联的次日记录,移除第一条打卡;否则保留原数据
          {
            $cond: [
              {
                $exists: {
                  $arrayElemAt: [
                    {
                      $filter: {
                        input: "$$ROOT",
                        as: "item",
                        cond: {
                          $and: [
                            { $or: [{ $eq: ["$$item.shift.shiftType.isNight", true] }, { $eq: ["$$item.shift.isNight", true] }] },
                            { $eq: ["$$item.nextDay", "$date"] }
                          ]
                        }
                      }
                    },
                    0
                  ]
                }
              },
              { $slice: ["$attendances", 1, { $size: "$attendances" }] },
              "$attendances"
            ]
          }
        ]
      },
      nextDay: 0,
      nextDayRecord: 0
    }
  }
])

关键步骤说明

  • $addFields:将当前记录的date转为日期类型后加一天,再转回YYYY-MM-DD格式的字符串,作为关联次日记录的标识
  • $lookup:自连接集合,通过nextDay匹配次日的考勤记录
  • $project:通过条件判断处理考勤数组:
    • 夜班记录:将自身考勤与次日记录的第一条打卡合并
    • 非夜班记录:如果它是某条夜班记录的次日,则移除已被合并的第一条打卡;否则保留原考勤数据

注意事项

  • 替换代码中的yourCollectionName为实际集合名称
  • 确保date字段是YYYY-MM-DD格式的字符串,若为Date类型需调整日期转换逻辑
  • 该查询支持多员工、多夜班场景的自动匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:42:37