Mongodb组文件并限制每组

时间:2016-10-14 15:55:39

标签: mongodb grouping limit aggregation-framework mongodb-aggregation

考虑这些文件:

{
    "Field1":"Test_1",
    "Speaker":1,
    "Listener":2,
    "ListenTime": ISODate("2016-10-15T14:17:49.336Z")
},
{
    "Field1":"Test_2",
    "Speaker":1,
    "Listener":2,
    "ListenTime": ISODate("2016-10-13T14:17:49.336Z")
},
{
    "Field1":"Test_3",
    "Speaker":1,
    "Listener":3,
    "ListenTime": ISODate("2016-10-10T14:10:49.336Z")
}

我要做的是在MongoDB(3.2)中使用单个查询仅提取由Speaker和Listener对它们进行分组的文档,仅使用最旧的ListenTime文档。
所以,在这种情况下,结果将是:

{
    "Field1":"Test_1",
    "Speaker":1,
    "Listener":2,
    "ListenTime": ISODate("2016-10-15T14:17:49.336Z")
},
{
    "Field1":"Test_3",
    "Speaker":1,
    "Listener":3,
    "ListenTime": ISODate("2016-10-10T14:10:49.336Z")
}

单个查询是否可以做到这一点?

2 个答案:

答案 0 :(得分:1)

聚合框架可用于实现此目的。在第一阶段,使用$group按Speaker和Listener对文档进行分组。在此阶段,使用$push运算符将组中的所有文档添加到列表中,并使用$max运算符计算最近的ListenTime。按照此$redact阶段,使用列表中最近的ListenTime保留文档。然后,使用$unwind阶段将列表展平为文档。然后,使用最终的$project阶段来获取所需的字段。

聚合查询将如下所示。

db.sampleCollection.aggregate([
    {
        "$group":{
            "_id":{"Speaker":"$Speaker", "Listener":"$Listener"}, 
            ListenTime : {"$max":"$ListenTime"}, 
            "docs":{"$push":"$$ROOT"}
        }
    },
    {
        $redact:{
            $cond:[{$eq:["$ListenTime","$$ROOT.ListenTime"]},"$$DESCEND","$$PRUNE"]
        }
    },

    {
        "$project":{
            "ListenTime":1, 
            "Field1":"$docs.0.Field1", 
            "Speaker":"$docs.0.Speaker", 
            "Listener":"$docs.0.Listener"
        }
    }
])

示例输出:

{
        "ListenTime" : ISODate("2016-10-10T14:10:49.336Z"),
        "Field1" : "Test_3",
        "Speaker" : 1,
        "Listener" : 3
}
{
        "ListenTime" : ISODate("2016-10-15T14:17:49.336Z"),
        "Field1" : "Test_1",
        "Speaker" : 1,
        "Listener" : 2
}

答案 1 :(得分:1)

运行以下聚合管道以获得所需的结果:

db.collection.aggregate([
    { "$sort": { "ListenTime": -1 } },
    {
        "$group": {
            "_id": {
                "Speaker": "$Speaker",
                "Listener": "$Listener"
            },
            "Field1" : { "$first": "$Field1" },
            "ListenTime" : { "$first": "$ListenTime" }
        }
    },
    {
        "$project": {
            "Field1": 1,
            "Speaker": "$_id.Speaker",
            "Listener": "$_id.Listener",
            "ListenTime": 1,
            "_id": 0
        }
    }
])

示例输出

/* 1 */
{
    "Field1" : "Test_3",
    "ListenTime" : ISODate("2016-10-10T14:10:49.336Z"),
    "Speaker" : 1,
    "Listener" : 3
}

/* 2 */
{
    "Field1" : "Test_1",
    "ListenTime" : ISODate("2016-10-15T14:17:49.336Z"),
    "Speaker" : 1,
    "Listener" : 2
}