在 MongoDB 聚合中添加缺失的日期

Posted

技术标签:

【中文标题】在 MongoDB 聚合中添加缺失的日期【英文标题】:Adding Missing Dates in MongoDB Aggregation 【发布时间】:2020-09-16 10:56:38 【问题描述】:

在这个问题中,我想获取以下时间范围的用户订阅

今天 本周 本月 今年

对于这个时间范围,我想显示所有可能日期的$group

[
   Dates: '2020-05-21', Count: 3, AverageIncome: 30 ,
   Dates: '2020-05-22', Count: 10, AverageIncome: 30 ,
   Dates: '2020-05-24', Count: 1, AverageIncome: 37 ,
   Dates: '2020-05-25', Count: 1, AverageIncome: 30 ,
   Dates: '2020-05-26', Count: 2, AverageIncome: 65 
]

我想添加缺失的日期以及将累加器数据设置为 0。例如,它应该是

[
   Dates: '2020-05-21', Count: 3, AverageIncome: 30 ,
   Dates: '2020-05-22', Count: 10, AverageIncome: 30 ,
   Dates: '2020-05-23', Count: 0, AverageIncome: 0 ,
   Dates: '2020-05-24', Count: 1, AverageIncome: 37 ,
   Dates: '2020-05-25', Count: 1, AverageIncome: 30 ,
   Dates: '2020-05-26', Count: 2, AverageIncome: 65 ,
   Dates: '2020-05-27', Count: 0, AverageIncome: 0 ,
   Dates: '2020-05-28', Count: 2, AverageIncome: 0 ,
]

PS:此时UTC时间为5月28日晚上11点45分

我正在使用的聚合管道阶段

const $agg = await Subscription.aggregate([
    
      $match: 
        createdOn: 
          $gte: moment(req.query.from).toDate(),
          $lte: moment(req.query.to).toDate()
        ,
        isCancelled: false
      
    ,

    
      $group: 
        _id: 
          $dateToString: 
            format: "%Y-%m-%d",
            date: "$createdOn"
          
        ,
        count:  $sum: 1 ,
        avgAmount:  $avg: "$amountPaid" 
      
    ,
    
      $project: 
        _id: false,
        sortKey: 
          $dateFromString: 
            dateString: "$_id"
          
        ,
        Dates: "$_id",
        Count: "$count",
        AverageIncome: "$avgAmount"
      
    ,
    
      $sort: 
        sortKey: 1
      
    ,
    
      $project: 
        sortKey: false
      
    
  ]);

【问题讨论】:

【参考方案1】:

前段时间我遇到过类似的问题,这是我遵循的方法:

function fillEmptyDates($agg, $defaultData, from, to) 
  const $aggObj = ; //Taking this as an object for easy checking

  $agg.map((agg) => 
    $aggObj[agg.Date] = agg; //Making an object from array entries with Date as key
  );

  const $loopDate = moment(from);
  const $endDate = moment(to);

  //Starting from from date to to date, checking if any date does not have entry in $aggObje
  while ($endDate.isSameOrAfter($loopDate)) 
    let $aggDate = $loopDate.format("YYYY-MM-DD");

    if (!$aggObj.hasOwnProperty($aggDate)) 
      //If any date does not have entry, creating a new entry from default aggregates and giving it the date as current date
      $aggObj[$aggDate] = 
        ...$defaultData,
        Date: $aggDate
      ;
    
    $loopDate.add(1, "day"); //Incrementing aggregate date
  

  //Converting back to array and sorting by date
  return Object.values($aggObj).sort((a, b) =>
    moment(a.Date).isBefore(moment(b.Date)) ? -1 : 1
  );
;

//You can call this function like so
$agg = fillEmptyDates(
            $agg, 
             Count: 0, AverageIncome: 0 ,
            req.query.from,
            req.query.to,
        )

【讨论】:

这是一个非常有用的答案,非常感谢

以上是关于在 MongoDB 聚合中添加缺失的日期的主要内容,如果未能解决你的问题,请参考以下文章

mongo聚合添加日期和总和

在 mongodb 本地时区聚合

使用 mongodb 聚合管道按升序向集合中的所有记录添加日期

Doctrine Mongodb ODM 在聚合中添加动态日期

如何使用 mongodb 聚合添加自定义字段?

mongoDB应用篇-mongo聚合查询