mongodb 聚合 - 具有最后一个日期的组

Posted

技术标签:

【中文标题】mongodb 聚合 - 具有最后一个日期的组【英文标题】:mongodb aggregation - group with last on date 【发布时间】:2017-10-30 22:02:40 【问题描述】:

我的 mongodb 集合包括 3 个字段:数字、日期、类型。 我想知道的是有多少文件包括其编号的最新日期并且类型=3。在 pasudo 代码中,我试图找到的内容如下所示:

Set<String> numbers; //set includes the numbers in the documents
int result = 0;
for each (String thisNumber: numbers)

    //find all the documents with this number
    List<Document> documentsWithThisNumber = collection.find(number: "$thisNumber");
    //find the one with the most recent date with this number
    documentsWithThisNumber = documentsWithThisNumber.sort();
    Document recentDate = documentsWithThisNumber.get(documentsWithThisNumber.size()-1);
    //if this recent document has type 3 we want to count it
    if (recentDate.getType()==3)
        result++;

我尝试构建一个按数字分组的查询,并获取每个数字的最后/最大日期并匹配其类型等于 3 的那些。由于该组只能包含累加器,因此我需要保存“类型”字段也用于匹配,我使用“第一个”累加器作为“类型”字段。我假设在它会为每个数字拾取带有最近事件的文档之后,这个累加器只会给我带来这个文档的类型。 我的查询是:

db.collection.aggregate([
$group: _id: "number" : "$number", "recentDate" : $max : "$date", 
"recentType" : $first : "$type",
$match: "recentType" : 3,
$count: "Qty"
],allowDiskUse: true);

这个查询的结果是错误的,另外我发现如果我将 $max 切换到 $min/$first/$last 或者如果我在“recentType”之后移动它 - 我仍然得到同样的错误结果,是什么让我认为“recentDate”根本不影响查询。

也许有人知道如何构建这样的查询?

【问题讨论】:

“最近日期有多少(原文如此)文档?” 是什么意思。什么是“约会”?是“今天”吗?是“最后一小时内”吗?日期通常与表示时间戳值的内容一起存储,该值基本上精确到毫秒。因此,除非该日期值本身在某个时间范围内“分组”,否则任何两个文档共享相同确切“时间戳”的可能性是无限小的。无论如何,这不是“一个查询”而是“两个”。一个是获取“最近日期”,另一个是根据它实际返回数据。 好吧,我想我被误解了。我将尝试再次解释我的问题:首先,日期是 iso 日期,因此 2 个文档可以共享相同的日期,但为了简化查询,他们不能并且日期是唯一的。其次,这就是我感兴趣的:每个数字可以有多个文档,具有不同/相等的日期和类型,我想查看具有最大日期的文档,如果该文档的类型等于 3 - 我想添加它到计数,如果没有 - 跳到下一个数字。 试试db.collection.aggregate([ $sort:number:1, date:1, $group: _id: "number" : "$number", "recent" : $last: date:"$$ROOT.date", type:"$$ROOT.type", $match: "recent.type" : 3, $count: "Qty" ]); 是的!这对我有用!非常感谢! 【参考方案1】:

给定如下所示的记录:

var r = [
      number: 12, type: 2, date: new ISODate("2017-10-30") 
     , number: 10, type: 2, date: new ISODate("2017-10-20") 
     , number: 12, type: 3, date: new ISODate("2017-10-30") 
     , number: 12, type: 3, date: new ISODate("2017-10-30") 
     , number: 12, type: 3, date: new ISODate("2017-10-30") 
     , number: 12, type: 3, date: new ISODate("2017-10-28") 
     , number: 12, type: 3, date: new ISODate("2017-10-15") 
     , number: 10, type: 3, date: new ISODate("2017-10-15") 
     , number: 10, type: 3, date: new ISODate("2017-10-15") 
     , number: 10, type: 3, date: new ISODate("2017-10-18") 
     , number: 10, type: 3, date: new ISODate("2017-10-18") 
     , number: 10, type: 3, date: new ISODate("2017-10-19") 
     , number: 10, type: 3, date: new ISODate("2017-10-19") 
     , number: 10, type: 3, date: new ISODate("2017-10-11") 
     ];

db.foo.insert(r);

那么这个管道就可以解决问题了。正如 Neil 指出的那样,在重新组织材料以获得最新日期之前,您必须首先获取具有相同编号的文档数量:

db.foo.aggregate([
$match: "type": 3
,$group: _id: number: "$number", date: "$date", n: $sum:1 
,$sort: "_id.date": -1
,$group: _id: "$_id.number", date: $first: "$_id.date", n: $first: "$n" 
            ]);

 "_id" : 10, "date" : ISODate("2017-10-19T00:00:00Z"), "n" : 2 
 "_id" : 12, "date" : ISODate("2017-10-30T00:00:00Z"), "n" : 3 

【讨论】:

我不明白您的问题。首先,我在最后只寻找一个数字,而您的查询结果是一个数字列表。其次,如果我有 2 个文档编号为“10”:最近的文档类型为“2”,而较早的文档类型为“3”——在这种情况下,我不想添加到我的计数中,因为最近的文档是键入“2”而不是“3”。所以我不能从匹配类型“3”的文档开始,因为那样我会丢失类型“2”的文档,并且不知道类型“3”的文档是带有最近日期的数字“ 10 英寸。

以上是关于mongodb 聚合 - 具有最后一个日期的组的主要内容,如果未能解决你的问题,请参考以下文章

具有特定条件计数的 Mongodb 聚合并按输出投影的日期范围过滤不能按预期工作

Python对象创建具有3个聚合关系成员的组

mongodb罗盘汇总$具有动态日期的匹配范围

将 Mongodb 中的日期与 C# LINQ 驱动程序进行比较

mongodb Aggregation聚合操作之$bucket

按日期排序聚合mongodb