使用$ last聚合并仅选择最高记录

时间:2013-12-27 18:56:39

标签: mongodb

我在MongoDB中有以下集合:

{
    "_id" : ObjectId("..."),
    "assetId" : "...",
    "date" : ISODate("..."),
    ...
}

我需要做很简单的事情 - 找到每个设备/资产的最新记录。我有以下查询:

db.collection.aggregate([ 
    { "$match" : { "assetId" : { "$in" : [ up_to_80_ids ]} } }, 
    { "$group" :{ "_id" : "$assetId" , "date" : { "$last" : "$date"}}}
])

整张桌子大概是20Gb。当我尝试执行此查询时,它需要大约8秒,这没有任何意义,只要我指定只应选择$ last记录。 assetId和date都被编入索引。如果我在群组之前添加 {$ sort:{date:1}} ,则不会更改任何内容。

基本上,我的查询结果不应该依赖于数据大小。我唯一需要的是每个设备/资产的最高记录。如果我做80个单独的查询,我需要几毫秒。

有没有办法让MongoDB不通过整个表?它看起来像数据库不会减少,但处理一切?!好吧,我知道这种行为应该有一些很好的理由,但我在文档或论坛上找不到任何内容。

更新:

最终找到了解释查询的正确语法2.4.6:

db.runCommand( { aggregate: "collection", pipeline : [...] , explain : true })

结果:

{
        "serverPipeline" : [
                {
                        "query" : {
                                "assetId" : {
                                        "$in" : [
                                                "52744d5722f8cb9b4f94d321",
                                                "52791fe322f8014b320dae41",
                                                "52740f5222f8cb9b4f94d306",
... must remove some because of SO limitations
                                                "52744d1722f8cb9b4f94d31d",
                                                "52744b1d22f8cb9b4f94d308",
                                                "52744ccd22f8cb9b4f94d319"
                                        ]
                                }
                        },
                        "projection" : {
                                "assetId" : 1,
                                "date" : 1,
                                "_id" : 0
                        },
                        "cursor" : {
                                "cursor" : "BtreeCursor assetId_1 multi",
                                "isMultiKey" : false,
                                "n" : 960881,
                                "nscannedObjects" : 960881,
                                "nscanned" : 960894,
                                "nscannedObjectsAllPlans" : 960881,
                                "nscannedAllPlans" : 960894,
                                "scanAndOrder" : false,
                                "indexOnly" : false,
                                "nYields" : 9,
                                "nChunkSkips" : 0,
                                "millis" : 6264,
                                "indexBounds" : {
                                        "assetId" : [
                                                [
                                                        "52740baa22f8cb9b4f94d2e8",
                                                        "52740baa22f8cb9b4f94d2e8"
                                                ],
                                                [
                                                        "52740bed22f8cb9b4f94d2e9",
                                                        "52740bed22f8cb9b4f94d2e9"
                                                ],
                                                [
                                                        "52740c3222f8cb9b4f94d2ea",
                                                        "52740c3222f8cb9b4f94d2ea"
                                                ],


                                                ....


                                                [
                                                        "5297770a22f82f9bdafce322",
                                                        "5297770a22f82f9bdafce322"
                                                ],
                                                [
                                                        "529df5f622f82f9bdafce429",
                                                        "529df5f622f82f9bdafce429"
                                                ],
                                                [
                                                        "529f6a6722f89deaabbf9881",
                                                        "529f6a6722f89deaabbf9881"
                                                ],
                                                [
                                                        "52a6e35122f89ce6e2cf4267",
                                                        "52a6e35122f89ce6e2cf4267"
                                                ]
                                        ]
                                },
                                "allPlans" : [
                                        {
                                                "cursor" : "BtreeCursor assetId_1 multi",
                                                "n" : 960881,
                                                "nscannedObjects" : 960881,
                                                "nscanned" : 960894,
                                                "indexBounds" : {
                                                        "assetId" : [
                                                                [
                                                                        "52740baa22f8cb9b4f94d2e8",
                                                                        "52740baa22f8cb9b4f94d2e8"
                                                                ],
                                                                [
                                                                        "52740bed22f8cb9b4f94d2e9",
                                                                        "52740bed22f8cb9b4f94d2e9"
                                                                ],
                                                                [
                                                                        "52740c3222f8cb9b4f94d2ea",
                                                                        "52740c3222f8cb9b4f94d2ea"
                                                                ],

                                                                .......

                                                                [
                                                                        "529df5f622f82f9bdafce429",
                                                                        "529df5f622f82f9bdafce429"
                                                                ],
                                                                [
                                                                        "529f6a6722f89deaabbf9881",
                                                                        "529f6a6722f89deaabbf9881"
                                                                ],
                                                                [
                                                                        "52a6e35122f89ce6e2cf4267",
                                                                        "52a6e35122f89ce6e2cf4267"
                                                                ]
                                                        ]
                                                }
                                        }
                                ],
                                "oldPlan" : {
                                        "cursor" : "BtreeCursor assetId_1 multi",
                                        "indexBounds" : {
                                                "assetId" : [
                                                        [
                                                                "52740baa22f8cb9b4f94d2e8",
                                                                "52740baa22f8cb9b4f94d2e8"
                                                        ],
                                                        [
                                                                "52740bed22f8cb9b4f94d2e9",
                                                                "52740bed22f8cb9b4f94d2e9"
                                                        ],
                                                        [
                                                                "52740c3222f8cb9b4f94d2ea",
                                                                "52740c3222f8cb9b4f94d2ea"
                                                        ],


                                                        ........


                                                        [
                                                                "529df5f622f82f9bdafce429",
                                                                "529df5f622f82f9bdafce429"
                                                        ],
                                                        [
                                                                "529f6a6722f89deaabbf9881",
                                                                "529f6a6722f89deaabbf9881"
                                                        ],
                                                        [
                                                                "52a6e35122f89ce6e2cf4267",
                                                                "52a6e35122f89ce6e2cf4267"
                                                        ]
                                                ]
                                        }
                                },
                                "server" : "351bcc56-1a25-61b7-a435-c14e06887015.local:27017"
                        }
                },
                {
                        "$group" : {
                                "_id" : "$assetId",
                                "date" : {
                                        "$last" : "$date"
                                }
                        }
                }
        ],
        "ok" : 1
}

3 个答案:

答案 0 :(得分:2)

您的explain输出表明您的$match阶段有960,881项与assetIds相匹配。 MongoDB使用assetId上的索引查找所有索引,并通过$group阶段将它们全部流式传输。这很贵。目前,MongoDB没有对聚合管道进行很多全流程优化,所以你写的就是你得到的,非常多。

MongoDB可以通过assetId升序和日期降序排序来优化此管道,然后应用SERVER-9507中建议的优化,但尚未实现。

目前,您最好的做法是为每个assetId执行此操作:

db.collection.find({assetId: THE_ID}).sort({date: -1}).limit(1)

答案 1 :(得分:0)

我不确定,但如果您在monngodb网站上阅读此link

它已注意 仅当$ group跟随$ sort操作时才使用$ last。否则,此操作的结果是不可预测的。

答案 2 :(得分:0)

我的程序遇到同样的问题。我已经尝试了mongoDB MapReduce,聚合框架等,但最后我停止使用索引扫描集合并在客户端上形成结果。但是现在收藏太大了,所以我想我会在你的问题中使用上面提到的许多小查询。它不是那么美丽,但它将是最快的解决方案恕我直言。

只有管道中的第一个查询使用索引。管道中的第二个查询接受第一个查询的输出,它很大而且没有索引。但正如Pipeline Operators and Indexes中提到的,您的查询可以使用复合索引,因此不太清楚。

我有一个想法:您可以尝试使用多个$or运算符而不是一个$in运算符 { "$match": { "$or": [{"assetId": <id1>}, {"assetId": <id2>...}] } }。据我所知,$or运算符可以并行执行,每个查询都可以使用索引。所以测试这个解决方案会很有趣。

P.S。如果找到这个问题的解决方案,我真的很高兴。