MongoDB嵌套数组按日期分组过滤查询需求
MongoDB按日期分组逾期预约解决方案
早上好!针对你提到的需求——查询所有逾期预约并按日期分组,我来一步步帮你梳理:
原始文档结构
你的MongoDB文档结构如下:
{ "company": "ESPIRAL", "osServico": [ { "_id": ObjectId("5afdbb931e511b23b621ff93"), "atend": [ { "aut": null, "_id": ObjectId("5afdc1369d845d25c5196044"), "tec": ObjectId("5af18fa5a0d18a0320149de4"), "data": ISODate("2018-05-16T00:00:00.000Z") }, { "aut": null, "_id": ObjectId("5afdc74a58f31a284d8d4d4f"), "tec": ObjectId("5af18fa5a0d18a0320149de4"), "data": ISODate("2018-05-16T00:00:00.000Z") }, { "aut": null, "_id": ObjectId("5afdc7b577ee6b28948137a8"), "tec": ObjectId("5ad9fdea68ab9f0014ddb5d2"), "data": ISODate("2018-05-15T00:00:00.000Z") } ] } ] }
期望的分组结果
你希望得到按日期拆分后的结果,每个日期对应一组逾期记录:
[ { "company": "ESPIRAL", "osServico": [ { "_id": ObjectId("5afdbb931e511b23b621ff93"), "atend": [ { "aut": null, "_id": ObjectId("5afdc7b577ee6b28948137a8"), "tec": ObjectId("5ad9fdea68ab9f0014ddb5d2"), "data": ISODate("2018-05-15T00:00:00.000Z") } ] } ] }, { "company": "ESPIRAL", "osServico": [ { "_id": ObjectId("5afdbb931e511b23b621ff93"), "atend": [ { "aut": null, "_id": ObjectId("5afdc1369d845d25c5196044"), "tec": ObjectId("5af18fa5a0d18a0320149de4"), "data": ISODate("2018-05-16T00:00:00.000Z") }, { "aut": null, "_id": ObjectId("5afdc74a58f31a284d8d4d4f"), "tec": ObjectId("5af18fa5a0d18a0320149de4"), "data": ISODate("2018-05-16T00:00:00.000Z") } ] } ] } ]
现有查询的问题
你当前的查询能过滤出逾期的atend记录,但缺少分组的核心步骤,所以无法按日期拆分结果:
[ { $match: { "osServico.atend.data": { $lt: data } } }, { $addFields: { "osServico": { "$map": { "input": "$osServico", "as": "os", "in": { "_id": "$$os._id", "servico": "$$os.servico", "atend": { "$filter": { "input": "$$os.atend", "as": "atend", "cond": { $and: [{ $lt: ["$$atend.data", data] }] } } } } } } } } ]
完整的聚合解决方案
要实现按日期分组,我们需要用$unwind展开嵌套数组,再用$group按日期聚合,最后重新构建文档结构,完整的聚合管道如下:
[ // 第一步:匹配包含逾期记录的文档(先缩小处理范围) { $match: { "osServico.atend.data": { $lt: data } } }, // 第二步:展开osServico数组,单独处理每个服务项 { $unwind: "$osServico" }, // 第三步:展开每个服务项下的atend数组,单独处理每条预约记录 { $unwind: "$osServico.atend" }, // 第四步:过滤出单条逾期的预约记录(确保只保留符合条件的项) { $match: { "osServico.atend.data": { $lt: data } } }, // 第五步:按日期+公司+服务ID分组,聚合同日期的逾期记录 { $group: { _id: { date: "$osServico.atend.data", company: "$company", osId: "$osServico._id" }, atendList: { $push: "$osServico.atend" } } }, // 第六步:重新构建成你期望的文档格式 { $project: { _id: 0, company: "$_id.company", osServico: [ { _id: "$_id.osId", atend: "$atendList" } ] } } ]
关键步骤说明:
- $unwind:把嵌套的
osServico和atend数组依次拆成单条文档,让每个预约记录都成为独立的处理单元,这是分组的前提。 - $group:以日期、公司、服务项ID为分组键,把同日期的所有逾期预约聚合到一个列表中,保证同一日期的记录会被归为一组。
- $project:重新整理输出结构,和你期望的格式完全对齐。
这样就能得到按日期分组的逾期预约结果啦~
内容的提问来源于stack exchange,提问作者Vinicius Spinellis
相关产品推荐
相关产品推荐

