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

MongoDB按日期合并shifts与attendances数组问题求助

MongoDB 按日期合并关联集合数据

我有三个MongoDB集合:users、attendances、shifts,需要通过users集合关联获取另外两个集合的数据。shifts集合有date字段,attendances集合有Date字段,希望按日期将这两类数据合并为一个数组,某类数据不存在时对应字段为null。

现有查询语句

User.aggregate([
  { $sort: { workerId: 1 } },
  {
    $lookup: {
      from: "shifts",
      localField: "_id",
      foreignField: "employeeId",
      pipeline: [
        {
          $match: {
            date: {
              $gte: new Date(fromDate),
              $lte: new Date(toDate),
            },
          },
        },
        {
          $project: {
            date: 1,
            shiftCode: 1,
          },
        },
        {
          $sort: {
            date: 1,
          },
        },
      ],
      as: "shifts",
    },
  },
  {
    $project: {
      _id: 1,
      workerId: 1,
      shiftListData: "$shifts",
    },
  },
  {
    $lookup: {
      from: "attendances",
      localField: "_id",
      foreignField: "employeeId",
      pipeline: [
        {
          $match: {
            Date: { $gte: new Date(fromDate), $lte: new Date(toDate) },
          },
        },
        {
          $project: {
            inTime: 1,
            name: 1,
            Date: 1,
          },
        },
      ],
      as: "attendances",
    },
  },
]);

当前输出

[
  {
    "workerId": "1005",
    "shiftListData": [
      {
        "_id": "63875e8182ebbe13ee9531d4",
        "shiftCode": "HOBGS_1100",
        "date": "2022-12-31T00:00:00.000Z"
      },
      {
        "_id": "63b277a2f6a8eccb2d95d407",
        "shiftCode": "WO",
        "date": "2023-01-01T00:00:00.000Z"
      },
      {
        "_id": "63b27787f6a8eccb2d95cf30",
        "shiftCode": "HOBGS_1100",
        "date": "2023-01-02T00:00:00.000Z"
      },
      {
        "_id": "63b277a2f6a8eccb2d95d409",
        "shiftCode": "HOBGS_1100",
        "date": "2023-01-03T00:00:00.000Z"
      }
    ],
    "attendances": [
      {
        "_id": "61307cd385b5055a15cec159",
        "Date": "2022-12-31T00:00:00.000Z",
        "inTime": "2022-12-31T11:16:10.000Z",
        "name": "name2"
      },
      {
        "_id": "63b236ef3980cffaf7715d62",
        "inTime": "2023-01-02T07:14:08.000Z",
        "Date": "2023-01-02T00:00:00.000Z",
        "name": "name2"
      }
    ]
  },
  {
    "workerId": "1006",
    "shiftListData": [
      {
        "_id": "63875e8182ebbe13ee9531d2",
        "shiftCode": "HOBGS_1100",
        "date": "2022-12-31T00:00:00.000Z"
      },
      {
        "_id": "63b277a2f6a8eccb2d95d403",
        "shiftCode": "WO",
        "date": "2023-01-01T00:00:00.000Z"
      },
      {
        "_id": "63b27787f6a8eccb2d95cf39",
        "shiftCode": "HOBGS_1100",
        "date": "2023-01-02T00:00:00.000Z"
      },
      {
        "_id": "63b277a2f6a8eccb2d95d400",
        "shiftCode": "HOBGS_1100",
        "date": "2023-01-03T00:00:00.000Z"
      }
    ],
    "attendances": [
      {
        "_id": "61307cd385b5055a15cec158",
        "Date": "2022-12-31T00:00:00.000Z",
        "inTime": "2022-12-31T11:16:10.000Z",
        "name": "name"
      },
      {
        "_id": "63b236ef3980cffaf7715d69",
        "inTime": "2023-01-02T07:14:08.000Z",
        "Date": "2023-01-02T00:00:00.000Z",
        "name": "name"
      }
    ]
  }
]

期望输出

[
  {
    "workerId": "1005",
    "newData": [
      {
        "_id": "63875e8182ebbe13ee9531d4",
        "shiftCode": "HOBGS_1100",
        "date": "2022-12-31T00:00:00.000Z",
        "attendanceId": "61307cd385b5055a15cec159",
        "attendanceDate": "2022-12-31T00:00:00.000Z",
        "inTime": "2022-12-31T11:16:10.000Z",
        "name": "name2"
      },
      {
        "_id": "63b277a2f6a8eccb2d95d407",
        "shiftCode": "WO",
        "date": "2023-01-01T00:00:00.000Z"
      },
      {
        "_id": "63b27787f6a8eccb2d95cf30",
        "shiftCode": "HOBGS_1100",
        "date": "2023-01-02T00:00:00.000Z",
        "attendanceId": "63b236ef3980cffaf7715d62",
        "inTime": "2023-01-02T07:14:08.000Z",
        "attendanceDate": "2023-01-02T00:00:00.000Z",
        "name": "name2"
      },
      {
        "_id": "63b277a2f6a8eccb2d95d409",
        "shiftCode": "HOBGS_1100",
        "date": "2023-01-03T00:00:00.000Z"
      }
    ]
  },
  {
    "workerId": "1006",
    "newData": [
      {
        "_id": "63875e8182ebbe13ee9531d2",
        "shiftCode": "HOBGS_1100",
        "date": "2022-12-31T00:00:00.000Z",
        "attendanceId": "61307cd385b5055a15cec158",
        "attendanceDate": "2022-12-31T00:00:00.000Z",
        "inTime": "2022-12-31T11:16:10.000Z",
        "name": "name"
      },
      {
        "_id": "63b277a2f6a8eccb2d95d403",
        "shiftCode": "WO",
        "date": "2023-01-01T00:00:00.000Z"
      },
      {
        "_id": "63b27787f6a8eccb2d95cf39",
        "shiftCode": "HOBGS_1100",
        "date": "2023-01-02T00:00:00.000Z",
        "attendanceId": "63b236ef3980cffaf7715d69",
        "inTime": "2023-01-02T07:14:08.000Z",
        "attendanceDate": "2023-01-02T00:00:00.000Z",
        "name": "name"
      },
      {
        "_id": "63b277a2f6a8eccb2d95d400",
        "shiftCode": "HOBGS_1100",
        "date": "2023-01-03T00:00:00.000Z"
      }
    ]
  }
]

解决方案

在现有聚合管道后添加以下阶段,即可实现按日期合并两类数据:

User.aggregate([
  { $sort: { workerId: 1 } },
  {
    $lookup: {
      from: "shifts",
      localField: "_id",
      foreignField: "employeeId",
      pipeline: [
        {
          $match: {
            date: {
              $gte: new Date(fromDate),
              $lte: new Date(toDate),
            },
          },
        },
        {
          $project: {
            date: 1,
            shiftCode: 1,
          },
        },
        {
          $sort: {
            date: 1,
          },
        },
      ],
      as: "shiftListData",
    },
  },
  {
    $lookup: {
      from: "attendances",
      localField: "_id",
      foreignField: "employeeId",
      pipeline: [
        {
          $match: {
            Date: { $gte: new Date(fromDate), $lte: new Date(toDate) },
          },
        },
        {
          $project: {
            attendanceId: "$_id",
            attendanceDate: "$Date",
            inTime: 1,
            name: 1,
            _id: 0,
          },
        },
      ],
      as: "attendances",
    },
  },
  // 转换考勤数据为日期映射对象,方便匹配
  {
    $addFields: {
      attendanceMap: {
        $arrayToObject: {
          $map: {
            input: "$attendances",
            as: "item",
            in: {
              k: { $dateToString: { format: "%Y-%m-%dT%H:%M:%S.%LZ", date: "$$item.attendanceDate" } },
              v: "$$item"
            }
          }
        }
      }
    }
  },
  // 遍历班次数据,合并对应考勤信息
  {
    $addFields: {
      newData: {
        $map: {
          input: "$shiftListData",
          as: "shift",
          in: {
            $mergeObjects: [
              "$$shift",
              { $ifNull: [ { $arrayElemAt: [ { $filter: { input: "$attendances", cond: { $eq: [ "$$this.attendanceDate", "$$shift.date" ] } } }, 0 ] }, {} ] }
            ]
          }
        }
      }
    }
  },
  // 保留需要的输出字段
  {
    $project: {
      workerId: 1,
      newData: 1,
      _id: 0
    }
  }
]);

代码说明

  1. 字段重命名:在考勤数据的$project阶段,将_id改为attendanceId、Date改为attendanceDate,避免与班次字段冲突。
  2. 考勤映射:通过$arrayToObject将考勤数组转为以日期字符串为键的对象,快速匹配对应日期的考勤数据。
  3. 数据合并:用$map遍历班次数据,通过$filter匹配同日期的考勤信息,再用$mergeObjects合并两类数据;无考勤数据时用空对象填充,对应字段自动为null或不显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 12:55:19