按ID分组Mongo文档,并按时间戳获取最新文档

时间:2016-04-13 15:52:45

标签: mongodb mongodb-query aggregation-framework

想象一下,我们在mongodb中存储了以下一组文档:

{ "fooId" : "1", "status" : "C", "timestamp" : ISODate("2016-01-03T00:00:00.000Z") "otherInfo" : "BAR", ... }
{ "fooId" : "2", "status" : "B", "timestamp" : ISODate("2016-01-02T00:00:00.000Z") "otherInfo" : "BAR", ... }
{ "fooId" : "3", "status" : "D", "timestamp" : ISODate("2016-01-04T00:00:00.000Z") "otherInfo" : "BAR", ... }

我想根据时间戳获取每个fooId的最新状态。因此,我的回报看起来像:

group

我一直试图通过使用db.collectionName.aggregate( [ { $sort: { timestamp: 1 } }, { $group: { _id: "$fooId", timestamp: { $last: "$timestamp" }, status: { "$last": "$status" }, otherInfo: { "$last": "$otherInfo" }, } } ] ) 运算符使用聚合来解决这个问题,但我想知道的部分有一种简单的方法可以从聚合中恢复整个文档,所以它看起来是一样的好像我使用了查找查询?看来你必须在分组时指定所有字段,如果文档上可以包含我可能不知道的可选字段,那么这似乎是不可扩展的。我当前的查询看起来像这样:

website_sale.checkout

3 个答案:

答案 0 :(得分:3)

如果您正在进行聚合,则需要执行与SQL类似的操作,这意味着指定每列的聚合操作,唯一的选择是使用$$ROOT运算符

db.test.aggregate(
   [
    { $sort: { timestamp: 1 } },
     {
       $group:
         {
           _id: "$fooId",
           timestamp: { $last: "$$ROOT" }
         }
     }
   ]
);

但这会稍微改变输出

{ "_id" : "1", "timestamp" : { "_id" : ObjectId("570e6be3e81c8b195818e7fa"), 
  "fooId" : "1", "status" : "A", "timestamp" :ISODate("2016-01-01T00:00:00Z"), 
  "otherInfo" : "BAR" } }

如果要返回原始文档格式,则可能需要一个$ project阶段

答案 1 :(得分:1)

您可以将$$ROOT系统变量与$last运算符一起使用,以返回最后一个文档。

db.collectionName.aggregate([      
    { "$sort": { "timestamp": 1 } },     
    { "$group": { 
        "_id": "$fooId",   
        "last_doc": { "$last": "$$ROOT" } 
    }}
])

当然,这将是每个组的最后一个文档作为字段的值。

{
        "_id" : "2",
        "doc" : {
                "_id" : ObjectId("570e6df92f5bb4fcc8bb177e"),
                "fooId" : "2",
                "status" : "B",
                "timestamp" : ISODate("2016-01-02T00:00:00Z")
        }
}

如果您对该输出不满意,那么当您只使用$push累加器运算符返回这些文档的数组时,最好的选择是在管道中添加另一个$group阶段。

db.collectionName.aggregate([      
    { "$sort": { "timestamp": 1 } },     
    { "$group": { 
        "_id": "$fooId",   
        "last_doc": { "$last": "$$ROOT" } 
    }},
    { "$group": { 
        "_id": null, 
        "result": { "$push": "$last_doc" } 
    }}

])

答案 2 :(得分:0)

虽然没有直接的方式来恢复原始文档但我没有看到任何价值,但请尝试关注聚合查询:

db.collection.aggregate([
   {$sort: {fooId:1, timestamp: -1}},
   {$group:{_id:"$fooId", doc:{$first:"$$ROOT"}}},
   {$project:{_id:0, doc:["$doc"]}}
]).forEach(function(item){

  printjson(item.doc[0]);

});

此查询将发出:

{ 
    "_id" : ObjectId("570e76d5e94e6584078f02c4"), 
    "fooId" : "2", 
    "status" : "B", 
    "timestamp" : ISODate("2016-01-02T00:00:00.000+0000"), 
    "otherInfo" : "BAR"
}
{ 
    "_id" : ObjectId("570e76d5e94e6584078f02c8"), 
    "fooId" : "3", 
    "status" : "D", 
    "timestamp" : ISODate("2016-01-04T00:00:00.000+0000"), 
    "otherInfo" : "BAR"
}
{ 
    "_id" : ObjectId("570e76d5e94e6584078f02c2"), 
    "fooId" : "1", 
    "status" : "C", 
    "timestamp" : ISODate("2016-01-03T00:00:00.000+0000"), 
    "otherInfo" : "BAR"
}