查找按今天,本周,本月分组的文档数

时间:2019-06-07 10:34:03

标签: mongodb aggregation-framework

我正在使用Redash进行数据可视化,并且我的文档结构如下:

{
"id" : "12345",
"created_at" : "07/06/19 08:53"
},
{
"id" : "123456",
"created_at" : "07/06/19 12:13" 
},
{
"id" : "123457",
"created_at" : "06/06/19 20:18"
}

我想要的结果是

{
"TimeRange" : "today",
"count" : "6"
},
{
"TimeRange" : "this Week",
"count" : 15
},
{
"TimeRange" : "this Month",
"count" : 40
}

我可以使用

按日期分组
db.doc.aggregate([
     { $group: 
        { _id: { $dateToString: { format: "%Y-%m-%d", date: "$created_at" } }, count: { $sum: 1 } } }
])  

但是有什么方法可以最好地使用聚合在指定的不同时间范围内显示结果?

1 个答案:

答案 0 :(得分:0)

这里的日期格式特别令人讨厌,因为它缺乏世纪和月份与日期的歧义。对于您而言,存储实际日期时间会更好,这样就可以轻松地进行日期操作。但是,对于本练习,让我们假设您不能。 MongoDB中的日期函数避免了假设,因此没有世纪以来的dateFromString格式组件,因此我们必须自己做。好。让我们从与您的数据相似的这组数据开始:

var r = [
         // Assume MM/DD/YY  where YY is 20YY
         // last week                                                           
         {"created_at" : "06/01/19 10:53"},

         // yesterday, this week                                                
         {"created_at" : "06/05/19 10:53"},

         // today                                                    
         {"created_at" : "06/06/19 08:53"},
         {"created_at" : "06/06/19 12:53"},
         {"created_at" : "06/06/19 18:33"},

         // tomorrow, this week                                                 
         {"created_at" : "06/07/19 19:33"},
         {"created_at" : "06/07/19 20:33"},

         // later, but this month                                               
         {"created_at" : "06/27/19 07:33"},
         {"created_at" : "06/27/19 08:33"},

         // next month                                                          
         {"created_at" : "07/04/19 11:33"},

         // next year                                                           
         {"created_at" : "07/04/20 11:33"}

    ];


要弄清楚今天,本月等,我们需要在存储的数据之外设置目标日期。

today = new ISODate("2019-06-06");
target_week = 22;   // up to you to implement
target_mon = today.getMonth() + 1;   // MongoDB mon is 1-12, not 0-11
target_year = today.getFullYear();

这是一个解决方案。我们可以使用快捷方式,只使用日期字符串的一部分,但是我们将构造一个实际的日期,该日期可以很好地设置为执行除特定请求的分组以外的其他操作。这意味着在将日期放入日期后,我们将把日期拖出日期。

db.foo.aggregate([

// Create a real date from the pieces.  Ignore time bits for now:               
{ $addFields: {"rd":
  {$dateFromParts : {
        "year": {$add: [2000,{$toInt: {$substr: ["$created_at",6,2]}} ] },
        "month":  {$toInt: {$substr: ["$created_at",0,2]}},
        "day":    {$toInt: {$substr: ["$created_at",3,2]}}
    }}
  }}

// Now use facet to act as a "multigroup":                                      
,{$facet: {
  "today": [
{$match: { "rd": today}}, {$count: "n"}
           ]

  ,"This week": [
{$project: { "w": {$week: "$rd"}, "y": {$year: "$rd"} }}
,{$match: { "w": target_week, "y": target_year}}
,{$count: "n"}
                 ]

  ,"This month": [
{$project: { "m": {$month: "$rd"}, "y": {$year: "$rd"} }}
,{$match: { "m": target_mon, "y": target_year}}
,{$count: "n"}
                  ]
    }}

  ,"This year": [
{$project: { "y": {$year: "$rd"} }}
,{$match: { "y": target_year}}
,{$count: "n"}
                  ]
    }}

]);

产生

{
    "today" : [
        {
            "n" : 3
        }
    ],
    "This week" : [
        {
            "n" : 6
        }
    ],
    "This month" : [
        {
            "n" : 9
        }
    ],
    "This year" : [
        {
            "n" : 10
        }
    ]
}