每个子文档的MongoDB日期差异,以及最终结果中的总和

时间:2018-02-17 09:50:49

标签: mongodb mongoose aggregation-framework

我的用户集合有一个数组字段,其中包含子文档,如bellow:

"training" : [ 
  {
    "id" : ObjectId("5a01867959e2868ce09fbbc5"),
    "startDate" : ISODate("2012-12-18T00:00:00.000Z"),
    "endDate" : ISODate("2015-05-31T00:00:00.000Z"),
    "inProgress" : false
  }, 
  {
    "id" : ObjectId("5a01899959e2868ce09fbbc6"),
    "startDate" : ISODate("2017-11-02T00:00:00.000Z"),
    "endDate" : ISODate("2017-11-25T00:00:00.000Z"),
    "inProgress" : false
  },
  {
    "id" : ObjectId("5a01899959e2868ce09fbbc8"),
    "startDate" : ISODate("2018-01-02T00:00:00.000Z"),
    "endDate" : null,
    "inProgress" : true
  }
],

我想要的是: 1-获取每个用户在年,月和日的总培训期(假设第一次培训的git差异,{year: 2, month: 6, day: 12},第二次培训{year: 0, month: 0, day: 23},以及当前正在进行的培训的最后一次培训减去日期,应为{year: 0, month: 1, day: 15}) 2-然后我应计算每个训练期的总和作为总训练期。

到目前为止我尝试过:

db.getCollection('user').aggregate([
   {$unwind: "$training"},
   {$project: {
      duration: {"$divide":[{$subtract: ['$training.to', '$education.from'] }, 1000 * 60 * 60 * 24 * 365]}
   }},
   {$group: {
     _id: '$_id',
     "duration": {$sum: '$duration'}  
   }}]
])

但是这个有以下问题: 1-不能分别以所需格式计算每个训练周期,并且不能计算那些周期的总和作为总训练周期。因为训练期间可能会中断。 2-不能计算进行中的训练持续时间。

1 个答案:

答案 0 :(得分:1)

添加了多个$addFields阶段,以减少和计算每次培​​训和总培训的天数,月数和年数差异。

这里的假设是1个月= 30天总是

db.data.aggregate(
    [
        {
            $addFields : {
                trainingPeriod : {
                    $map : {
                        input : "$training",
                        as : "t",
                        in : {
                            year: {$subtract: [{$year : {$ifNull : ["$$t.endDate", new Date()]}}, {$year : "$$t.startDate"}]},
                            month: {$subtract: [{$month : {$ifNull : ["$$t.endDate", new Date()]}}, {$month : "$$t.startDate"}]},
                            dayOfMonth: {$subtract: [{$dayOfMonth : {$ifNull : ["$$t.endDate", new Date()]}}, {$dayOfMonth : "$$t.startDate"}]}
                        }
                    }
                }
            }
        },
        {
            $addFields : {
                trainingPeriod : {
                    $map : {
                        input : "$trainingPeriod",
                        as : "d",
                        in : {
                            year: "$$d.year",
                            month: {$cond : [{$lt : ["$$d.dayOfMonth", 0]}, {$subtract : ["$$d.month", 1]}, "$$d.month" ]},
                            day: {$cond : [{$lt : ["$$d.dayOfMonth", 0]}, {$add : [30, "$$d.dayOfMonth"]}, "$$d.dayOfMonth" ]}
                        }
                    }
                }
            }
        },
        {
            $addFields : {
                trainingPeriod : {
                    $map : {
                        input : "$trainingPeriod",
                        as : "d",
                        in : {
                            year: {$cond : [{$lt : ["$$d.month", 0]}, {$subtract : ["$$d.year", 1]}, "$$d.year" ]},
                            month: {$cond : [{$lt : ["$$d.month", 0]}, {$add : [12, "$$d.month"]}, "$$d.month" ]},
                            day: "$$d.day"
                        }
                    }
                }
            }
        },
        {
            $addFields : {
                total : {
                    $reduce : {
                        input : "$trainingPeriod",
                        initialValue : {year : 0, month : 0, day : 0},
                        in : {
                            year: {$add : ["$$this.year", "$$value.year"]},
                            month: {$add : ["$$this.month", "$$value.month"]},
                            day: {$add : ["$$this.day", "$$value.day"]}
                        }
                    }
                }
            }
        },
        {
            $addFields : {
                total : {
                    year : "$total.year",
                    month : {$add : ["$total.month", {$floor : {$divide : ["$total.day", 30]}}]},
                    day : {$mod : ["$total.day", 30]}
                }
            }
        },
        {
            $addFields : {
                total : {
                    year : {$add : ["$total.year", {$floor : {$divide : ["$total.month", 12]}}]},
                    month : {$mod : ["$total.month", 12]},
                    day : "$total.day"
                }
            }
        }
    ]
).pretty()

结果

{
    "_id" : ObjectId("5a87fcf68a2c0b7c0666140f"),
    "training" : [
        {
            "id" : ObjectId("5a01867959e2868ce09fbbc5"),
            "startDate" : ISODate("2012-12-18T00:00:00Z"),
            "endDate" : ISODate("2015-05-31T00:00:00Z"),
            "inProgress" : false
        },
        {
            "id" : ObjectId("5a01899959e2868ce09fbbc6"),
            "startDate" : ISODate("2017-11-02T00:00:00Z"),
            "endDate" : ISODate("2017-11-25T00:00:00Z"),
            "inProgress" : false
        },
        {
            "id" : ObjectId("5a01899959e2868ce09fbbc8"),
            "startDate" : ISODate("2018-01-02T00:00:00Z"),
            "endDate" : null,
            "inProgress" : true
        }
    ],
    "trainingPeriod" : [
        {
            "year" : 2,
            "month" : 5,
            "day" : 13
        },
        {
            "year" : 0,
            "month" : 0,
            "day" : 23
        },
        {
            "year" : 0,
            "month" : 1,
            "day" : 16
        }
    ],
    "total" : {
        "year" : 2,
        "month" : 7,
        "day" : 22
    }
}
>