mongo聚合添加日期和总和

时间:2018-03-08 05:25:51

标签: javascript node.js mongodb mongoose aggregation

我觉得这可能真的很复杂。我知道这可以在JS中通过获取每条记录,确定几个月的差异,然后在一个for循环中将每个model.month增加1,在一个月差异达到之后停止。我只是无法围绕聚合的可能性。任何帮助都会成为救星!

这是我的数据:

{
   model: car
   serial: bbbaaa
   warranty_start_date: 03/05/2018
   warranty_end_date: 06/16/2018
},
{
   model: car
   serial: jjjwww
   warranty_start_date: 03/02/2018
   warranty_end_date: 05/20/2018
},
{
   model: truck
   serial: tttvvv
   warranty_start_date: 05/06/2016
   warranty_end_date: 07/15/2016
}

这就是我希望它最终结束的方式:

{
  model: car
  in_warranty_these_months: { 03/2018: 2, 04/2018: 2, 05/2018: 2, 06/2018: 1 } 
},
{
  model: truck
  in_warranty_these_months: { 05/2016: 1, 06/2016: 1, 07/2016: 1 } 
}

更新的 在@mickl的帮助下, 下面的代码就像一个魅力:

 db.col.aggregate([
    {
        $addFields: {
            monthsRange: {
                $range: [ 
                    { $add: [ 
                        { $multiply: [12, {$year: "$warranty_start_date"}] }, 
                        {$month: "$warranty_start_date"} ] 
                    }, 
                    { $add: [ 
                        { $multiply: [12, {$year: "$warranty_end_date"}] }, 
                        { $add: [{$month: "$warranty_end_date"}, 1] } ] 
                    }, 1]
            }
        }
    },
    {
        $unwind: "$monthsRange"
    },
    {
        $group: {
            _id: { model: "$model", month: "$monthsRange" },
            count: {$sum:1}
        }
    },
    {
      $group: {
        _id: "$_id.model",
        pairs: {
          $push: {          
            k: {
              $dateToString: {
                format: "%m_%Y",
                date: {
                  $dateFromParts: {
                    day: 1,
                    month: {
                      $cond: [{
                        $eq: [0, {
                          $mod: ["$_id.month", 12]
                        }]
                      }, {
                        $trunc: 12
                      }, {
                        $mod: ["$_id.month", 12]
                      }]
                    },
                    year: {
                      $cond: [{
                        $eq: [0, {
                          $mod: ["$_id.month", 12]
                        }]
                      }, {
                        $subtract: [{
                          $trunc: {
                            $divide: ["$_id.month", 12]
                          }
                        }, 1]
                      }, {
                        $trunc: {
                          $divide: ["$_id.month", 12]
                        }
                      }]
                    }
                  }
                }
              }
            },
            v: "$count"
          }
        }
      }
    },
    {
            $project: {
                _id: 0,
                model: "$_id",
                in_warranty_these_months: {
                    $arrayToObject: "$pairs"
                }
            }
        }
    ])

1 个答案:

答案 0 :(得分:1)

您可以使用以下聚合:

db.col.aggregate([
    {
        $addFields: {
            monthsRange: {
                $range: [ 
                    { $add: [ 
                        { $multiply: [12, {$year: "$warranty_start_date"}] }, 
                        {$month: "$warranty_start_date"} ] 
                    }, 
                    { $add: [ 
                        { $multiply: [12, {$year: "$warranty_end_date"}] }, 
                        { $add: [{$month: "$warranty_end_date"}, 1] } ] 
                    }, 1]
            }
        }
    },
    {
        $unwind: "$monthsRange"
    },
    {
        $group: {
            _id: { model: "$model", month: "$monthsRange" },
            count: {$sum:1}
        }
    },
    {
        $group: {
            _id: "$_id.model",
            pairs: {
                $push: {
                    k: { 
                        $dateToString: {
                            format: "%m/%Y",
                            date: {
                                $dateFromParts: { 
                                    day: 1, 
                                    month: { $add: [{ $mod: [ "$_id.month", 12 ] }, 1] }, 
                                    year: { $trunc: { $divide: [ "$_id.month", 12 ] } }
                                } 
                            }
                        }                        
                    },
                    v: "$count"
                }
            }
        }
    },
    {
        $project: {
            _id: 0,
            model: "$_id",
            in_warranty_these_months: {
                $arrayToObject: "$pairs"
            }
        }
    }
])

基本上你必须根据你的日期生成范围(使用$range)。为此,您可以根据以下公式将日期转换为数字:12 *year + month。这将使您可以使用$ range为第一个文档生成四个值,为第二个文档生成三个值等等。

然后,您可以使用$group计算每个模型的每个月。

在上一步中,我们要使用$arrayToObject,因此我们必须将数据转换为具有两个属性kv的对象。为此,我们必须使用$dateFromParts$dateToString

将我们的数字转换回所需的格式