【问题标题】:Adding Missing Dates in MongoDB Aggregation在 MongoDB 聚合中添加缺失的日期
【发布时间】: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
      }
    }
  ]);

【问题讨论】:

    标签: node.js mongoose aggregation-framework


    【解决方案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,
            )
    

    【讨论】:

    • 这是一个非常有用的答案,非常感谢
    猜你喜欢
    • 2022-10-23
    • 2020-06-19
    • 1970-01-01
    • 2023-03-07
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多