我应该使用mapReduce上的聚合作为一段时间的总和吗?

时间:2018-01-24 18:05:10

标签: mongodb mapreduce aggregation-framework aggregate

对于reviews集合,我获得了以下架构的文档:

{
    "_id" : ObjectId("5a664ad3f7a901880a17128a"),
    "location" : "11350009624574901029",
    "account" : "113603894122287361289",
    "comment" : "Above par sushi place for the mid-west. Down side: server forgot our order, twice. He was apologetic and did comp our drinks. \n\nP.S. no warm sake......",
    "updateTime" : ISODate("2018-01-17T04:12:13.859Z"),
    "reviewId" : "AIe9_BGlY-BaOO_aND3JZqxJBS1RA3z9eVPZzQSvV3xv13QOiWzAIy3bxebaQBfADIo85qB6DKjJ2L9hDZusd4D6laJpxuQns7pDij3FBbKAAMiGyE7L8s8",
    "starRating" : "THREE",
    "starRatingNumber" : 3,
    "reviewer" : {
        "displayName" : "alpha landingham"
    },
    "reviewReply" : {
        "comment" : "Hey there! Gosh, I'm sorry to hear that your server forgot your order once, let alone twice! I'm also quite surprised to hear about the sake - we never run out of warm sake. I'd love to dig into this a bit further. Would you please email me directly? You can reach me at Sarah@FRG.rest. Kindly, Sarah",
        "updateTime" : "2017-09-25T13:49:20.443714Z"
    },
    "createTime" : ISODate("2017-09-18T22:02:14.348Z")
}

我想知道拿出所有文件并按日期汇总,一天,一周和一个月进行一些分组。基本上我想知道一些日期聚合的评论数量是多少。

我试过了:

[
   {
      "$match":{
         "account":"113603894122287361289",
         "location":"17198095624181011587"
      }
   },
   {
      "$project":{
         "account":1,
         "starRatingNumber":1,
         "updateTime":1,
         "createTime":1,
         "location":1
      }
   },
   {
      "$group":{
         "total":{
            "$sum":1
         },
         "rating":{
            "$avg":"$starRatingNumber"
         },
         "_id":{
            "month":{
               "$month":"$updateTime"
            },
            "year":{
               "$year":"$updateTime"
            }
         }
      }
   },
   {
      "$project":{
         "rating":1,
         "updateTime":1,
         "total":1,
         "date_aggregates":"$_id",
         "date":1,
         "_id":0,
         "createTime":1
      }
   }
]

但是,它只给出了每个日期分组的总和,而不是每个日期的总和。

例如,如果我有:

  • 1月2日的点评
  • 二月的10条评论
  • 7月的点评

我想获得类似的东西:

  • 2月1日的评论
  • 12条评论至Frebruary
  • 截至3月的19条评论

我想说我想要累积COUNT,我应该如何修改聚合管道?我应该切换到mapReduce方法作为这样做的唯一方法吗?

1 个答案:

答案 0 :(得分:1)

为简化解决方案,假设您有一个这样的集合(例如,由于某些聚合阶段):

db.col.save({ _id: { month: 1, year: 2017 }, total: 2 });
db.col.save({ _id: { month: 2, year: 2017 }, total: 10 });
db.col.save({ _id: { month: 3, year: 2017 }, total: 7 });

要计算每年的累积总和,您应该在聚合以下运行:

db.col.aggregate([
    {
        $group: {
            _id: "$_id.year",
            items: { $push: "$_id" },
            totals: { $push: "$total" }
        }
    },
    {
        $unwind: { path: "$items", includeArrayIndex: "arrayIndex" }
    },
    {
        $project: {
            _id: 0,
            year: "$items.year",
            month: "$items.month",
            total: {
                $let: {
                   vars: {
                      arr: { $slice: [ "$totals", { $add: [ "$arrayIndex", 1 ] } ] }
                   },
                   in: {
                       $reduce: {
                          input: "$$arr",
                          initialValue: 0,
                          in: { $add : ["$$value", "$$this"] }
                       }
                    }
                }
             }
        }
    }
])

说明:

  • 最初我们需要在一年内拥有所有项目的上下文,这就是我们开始分组的原因(假设项目按月排序)
  • includeArrayIndex$unwind的特殊参数,它会为每个月分配后续数字(如果您有全年统计数据,理论上不需要)
  • 通过向该索引添加1,我们可以确定此特定月份的总和中应包含的总数
  • 使用$slice我们可以获取数组的第一个n元素(包含所有订购月份的总数)
  • $reduce是我们计算数组中元素总和所需的方法