MongoDB按标签合并文档并生成年度对比字段的实现方案
解决MongoDB按类别合并年度数据的需求
我来帮你搞定这个按medicalreimbursementDateFamlyLabel合并年度数据的需求——把同类别下的当前年度数据和上一年度数据整合到一个文档里,没有上一年度数据的字段就填0。我们可以用MongoDB的聚合管道来完成这个操作,下面是具体的实现步骤和代码:
实现思路
- 按
medicalreimbursementDateFamlyLabel分组,把同类别下的所有年度数据归集到一起; - 从分组后的数组里分离出目标年度和上一年度的数据;
- 构造最终输出文档:直接使用目标年度的字段值,上一年度的字段添加
_previousYear后缀,没有对应数据的字段填充0。
聚合管道代码
假设我们的集合名为medical_reimbursements,目标年度是2019,上一年度是2018,执行以下聚合命令:
db.medical_reimbursements.aggregate([ // 第一步:按类别分组,收集同类别下的所有文档 { $group: { _id: "$medicalreimbursementDateFamlyLabel", docs: { $push: "$$ROOT" } } }, // 第二步:分离目标年度和上一年度的数据 { $project: { _id: 0, medicalreimbursementDateFamlyLabel: "$_id", // 获取目标年度(2019)的文档,无数据则返回空对象 targetYearDoc: { $arrayElemAt: [ { $filter: { input: "$docs", cond: { $eq: ["$$this.year", 2019] } } }, 0 ] }, // 获取上一年度(2018)的文档,无数据则返回空对象 previousYearDoc: { $arrayElemAt: [ { $filter: { input: "$docs", cond: { $eq: ["$$this.year", 2018] } } }, 0 ] } } }, // 第三步:构造最终输出字段,处理空值为0 { $project: { medicalreimbursementDateFamlyLabel: 1, // 上一年度字段,无数据则填0 numberOfActs_previousYear: { $ifNull: ["$previousYearDoc.numberOfActs", 0] }, totalRealCharges_previousYear: { $ifNull: ["$previousYearDoc.totalRealCharges", 0] }, totalSSReimbursement_previousYear: { $ifNull: ["$previousYearDoc.totalSSReimbursement", 0] }, totalDelegatePayment_previousYear: { $ifNull: ["$previousYearDoc.totalDelegatePayment", 0] }, totalOtherReimbursement_previousYear: { $ifNull: ["$previousYearDoc.totalOtherReimbursement", 0] }, insuredUsersNumber_previousYear: { $ifNull: ["$previousYearDoc.insuredUsersNumber", 0] }, // 目标年度字段,无数据则填0 numberOfActs: { $ifNull: ["$targetYearDoc.numberOfActs", 0] }, totalRealCharges: { $ifNull: ["$targetYearDoc.totalRealCharges", 0] }, totalSSReimbursement: { $ifNull: ["$targetYearDoc.totalSSReimbursement", 0] }, totalDelegatePayment: { $ifNull: ["$targetYearDoc.totalDelegatePayment", 0] }, totalOtherReimbursement: { $ifNull: ["$targetYearDoc.totalOtherReimbursement", 0] }, insuredUsersNumber: { $ifNull: ["$targetYearDoc.insuredUsersNumber", 0] } } } ])
代码解释
- $group阶段:把所有相同
medicalreimbursementDateFamlyLabel的文档放到docs数组里,方便后续统一处理; - 第二阶段$project:用
$filter筛选对应年份的文档,再用$arrayElemAt取出数组中的唯一文档(每个类别每个年份只会有一条数据),无对应年份数据时返回空对象; - 第三阶段$project:用
$ifNull判断字段是否存在,不存在就填充0,同时给上一年度的字段加上_previousYear后缀,最终输出你需要的结构。
适配你的示例结果说明
你给出的示例结果里,Optique和Hospitalisation的当前年度字段填了0,这说明你的目标年度应该是2018,上一年度是2017。只需要把聚合管道里的年份参数改成2018和2017,就能得到你想要的输出:
[ { "medicalreimbursementDateFamlyLabel": "Pharmacie", "numberOfActs_previousYear": 160, "totalRealCharges_previousYear": 882.3299999999999, "totalSSReimbursement_previousYear": 521.63, "totalDelegatePayment_previousYear": 360.42, "totalOtherReimbursement_previousYear": 0, "insuredUsersNumber_previousYear": 80, "numberOfActs": 100, "totalRealCharges": 784.2, "totalSSReimbursement": 122, "totalDelegatePayment": 230.35, "totalOtherReimbursement": 12, "insuredUsersNumber": 56 }, { "medicalreimbursementDateFamlyLabel": "Optique", "numberOfActs_previousYear": 33, "totalRealCharges_previousYear": 6282, "totalSSReimbursement_previousYear": 158.5, "totalDelegatePayment_previousYear": 4919.46, "totalOtherReimbursement_previousYear": 270, "insuredUsersNumber_previousYear": 21, "numberOfActs": 0, "totalRealCharges": 0, "totalSSReimbursement": 0, "totalDelegatePayment": 0, "totalOtherReimbursement": 0, "insuredUsersNumber": 0 }, { "medicalreimbursementDateFamlyLabel": "Hospitalisation", "numberOfActs_previousYear": 1437, "totalRealCharges_previousYear": 129477.12, "totalSSReimbursement_previousYear": 60697.87, "totalDelegatePayment_previousYear": 63864.41, "totalOtherReimbursement_previousYear": 3523.2999999999997, "insuredUsersNumber_previousYear": 279, "numberOfActs": 0, "totalRealCharges": 0, "totalSSReimbursement": 0, "totalDelegatePayment": 0, "totalOtherReimbursement": 0, "insuredUsersNumber": 0 } ]
内容的提问来源于stack exchange,提问作者Iliyan Yordanov
相关产品推荐
相关产品推荐

