limit()和sort()对pymongo和mongodb进行排序



尽管阅读了人们的回答,说排序是先完成的,但有证据表明,限制是在排序之前完成的。有没有办法强制排序总是先完成的?

views = mongo.db.view_logging.find().sort([('count', 1)]).limit(10)

无论我使用.sort().limit()还是.limit().sort(),限制都优先。我想知道这是否与pymongo有关。。。

根据文档,无论命令链中哪一个先出现,sort()总是在limit()之前应用

您还可以研究查询的.explain()结果并查看执行阶段——您会发现排序输入阶段会检查所有筛选的文档(在您的情况下是集合中的所有文档),然后应用限制。


让我们来举个例子。

假设有一个foo数据库,其中test集合包含6个文档:

>>> col = db.foo.test
>>> for doc in col.find():
...     print(doc)
{'time': '2016-03-28 12:12:00', '_id': ObjectId('56f9716ce4b05e6b92be87f2'), 'value': 90}
{'time': '2016-03-28 12:13:00', '_id': ObjectId('56f971a3e4b05e6b92be87fc'), 'value': 82}
{'time': '2016-03-28 12:14:00', '_id': ObjectId('56f971afe4b05e6b92be87fd'), 'value': 75}
{'time': '2016-03-28 12:15:00', '_id': ObjectId('56f971b7e4b05e6b92be87ff'), 'value': 72}
{'time': '2016-03-28 12:16:00', '_id': ObjectId('56f971c0e4b05e6b92be8803'), 'value': 81}
{'time': '2016-03-28 12:17:00', '_id': ObjectId('56f971c8e4b05e6b92be8806'), 'value': 90}

现在,让我们执行具有不同顺序的sort()limit()的查询,并检查结果和解释计划。

排序然后限制:

>>> from pprint import pprint
>>> cursor = col.find().sort([('time', 1)]).limit(3)  
>>> sort_limit_plan = cursor.explain()
>>> pprint(sort_limit_plan)
{u'executionStats': {u'allPlansExecution': [],
                     u'executionStages': {u'advanced': 3,
                                          u'executionTimeMillisEstimate': 0,
                                          u'inputStage': {u'advanced': 6,
                                                          u'direction': u'forward',
                                                          u'docsExamined': 6,
                                                          u'executionTimeMillisEstimate': 0,
                                                          u'filter': {u'$and': []},
                                                          u'invalidates': 0,
                                                          u'isEOF': 1,
                                                          u'nReturned': 6,
                                                          u'needFetch': 0,
                                                          u'needTime': 1,
                                                          u'restoreState': 0,
                                                          u'saveState': 0,
                                                          u'stage': u'COLLSCAN',
                                                          u'works': 8},
                                          u'invalidates': 0,
                                          u'isEOF': 1,
                                          u'limitAmount': 3,
                                          u'memLimit': 33554432,
                                          u'memUsage': 213,
                                          u'nReturned': 3,
                                          u'needFetch': 0,
                                          u'needTime': 8,
                                          u'restoreState': 0,
                                          u'saveState': 0,
                                          u'sortPattern': {u'time': 1},
                                          u'stage': u'SORT',
                                          u'works': 13},
                     u'executionSuccess': True,
                     u'executionTimeMillis': 0,
                     u'nReturned': 3,
                     u'totalDocsExamined': 6,
                     u'totalKeysExamined': 0},
 u'queryPlanner': {u'indexFilterSet': False,
                   u'namespace': u'foo.test',
                   u'parsedQuery': {u'$and': []},
                   u'plannerVersion': 1,
                   u'rejectedPlans': [],
                   u'winningPlan': {u'inputStage': {u'direction': u'forward',
                                                    u'filter': {u'$and': []},
                                                    u'stage': u'COLLSCAN'},
                                    u'limitAmount': 3,
                                    u'sortPattern': {u'time': 1},
                                    u'stage': u'SORT'}},
 u'serverInfo': {u'gitVersion': u'6ce7cbe8c6b899552dadd907604559806aa2e9bd',
                 u'host': u'h008742.mongolab.com',
                 u'port': 53439,
                 u'version': u'3.0.7'}}

限制然后排序:

>>> cursor = col.find().limit(3).sort([('time', 1)])
>>> limit_sort_plan = cursor.explain()
>>> pprint(limit_sort_plan)
{u'executionStats': {u'allPlansExecution': [],
                     u'executionStages': {u'advanced': 3,
                                          u'executionTimeMillisEstimate': 0,
                                          u'inputStage': {u'advanced': 6,
                                                          u'direction': u'forward',
                                                          u'docsExamined': 6,
                                                          u'executionTimeMillisEstimate': 0,
                                                          u'filter': {u'$and': []},
                                                          u'invalidates': 0,
                                                          u'isEOF': 1,
                                                          u'nReturned': 6,
                                                          u'needFetch': 0,
                                                          u'needTime': 1,
                                                          u'restoreState': 0,
                                                          u'saveState': 0,
                                                          u'stage': u'COLLSCAN',
                                                          u'works': 8},
                                          u'invalidates': 0,
                                          u'isEOF': 1,
                                          u'limitAmount': 3,
                                          u'memLimit': 33554432,
                                          u'memUsage': 213,
                                          u'nReturned': 3,
                                          u'needFetch': 0,
                                          u'needTime': 8,
                                          u'restoreState': 0,
                                          u'saveState': 0,
                                          u'sortPattern': {u'time': 1},
                                          u'stage': u'SORT',
                                          u'works': 13},
                     u'executionSuccess': True,
                     u'executionTimeMillis': 0,
                     u'nReturned': 3,
                     u'totalDocsExamined': 6,
                     u'totalKeysExamined': 0},
 u'queryPlanner': {u'indexFilterSet': False,
                   u'namespace': u'foo.test',
                   u'parsedQuery': {u'$and': []},
                   u'plannerVersion': 1,
                   u'rejectedPlans': [],
                   u'winningPlan': {u'inputStage': {u'direction': u'forward',
                                                    u'filter': {u'$and': []},
                                                    u'stage': u'COLLSCAN'},
                                    u'limitAmount': 3,
                                    u'sortPattern': {u'time': 1},
                                    u'stage': u'SORT'}},
 u'serverInfo': {u'gitVersion': u'6ce7cbe8c6b899552dadd907604559806aa2e9bd',
                 u'host': u'h008742.mongolab.com',
                 u'port': 53439,
                 u'version': u'3.0.7'}}

正如您所看到的,在这两种情况下,排序都会首先应用,并影响所有6个文档,然后限制将结果限制为3个。

而且,执行计划完全相同

>>> from copy import deepcopy  # just in case
>>> cursor = col.find().sort([('time', 1)]).limit(3)
>>> sort_limit_plan = deepcopy(cursor.explain())
>>> cursor = col.find().limit(3).sort([('time', 1)])
>>> limit_sort_plan = deepcopy(cursor.explain())
>>> sort_limit_plan == limit_sort_plan
True

另请参阅:

  • 如何告诉Mongo在限制结果之前对集合进行排序

mongodb文档指出skip()方法控制结果集的起点,然后是sort(),最后是limit()方法。

这与代码的顺序无关。原因是mongo获取了查询的所有方法,然后按照这个确切的顺序对skip-sort-limit方法进行排序,然后运行查询。

我怀疑,您在排序参数中传递了错误的键。类似于"$key_name"而不仅仅是"key_name"

请参阅如何告诉Mongo在限制结果之前对集合进行排序?与您的相同问题的解决方案

从逻辑上讲,它应该是管道中最先出现的东西,但MongoDB总是在限制之前先排序。

在我的测试中,排序操作优先,无论它是在跳过之前还是之后。然而,对我来说,这似乎是一种非常奇怪的行为

我的样本数据集是:

[
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef81"), 
        "number" : 48.98052410874508
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef82"), 
        "number" : 50.98747461471063
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef83"), 
        "number" : 81.32911244349772
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef84"), 
        "number" : 87.95549919039071
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef85"), 
        "number" : 81.63582683594402
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef86"), 
        "number" : 43.25696270026136
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef87"), 
        "number" : 88.22046335409453
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef88"), 
        "number" : 64.00556739160076
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef89"), 
        "number" : 16.09353150244296
    }, 
    {
        "_id" : ObjectId("56f845fea524b4d098e0ef8a"), 
        "number" : 17.46667776660574
    }
]

Python测试代码:

import pymongo
client = pymongo.MongoClient("mongodb://localhost:27017")
database = client.get_database("test")
collection = database.get_collection("collection")
print("----------------[limit -> sort]--------------------------")
result = collection.find().limit(5).sort([("number", pymongo.ASCENDING)])
for r in result:
    print(r)
print("----------------[sort -> limit]--------------------------")
result = collection.find().sort([("number", pymongo.ASCENDING)]).limit(5)
for r in result:
    print(r)

结果:

----------------[limit -> sort]--------------------------
{u'_id': ObjectId('56f845fea524b4d098e0ef89'), u'number': 16.09353150244296}
{u'_id': ObjectId('56f845fea524b4d098e0ef8a'), u'number': 17.46667776660574}
{u'_id': ObjectId('56f845fea524b4d098e0ef86'), u'number': 43.25696270026136}
{u'_id': ObjectId('56f845fea524b4d098e0ef81'), u'number': 48.98052410874508}
{u'_id': ObjectId('56f845fea524b4d098e0ef82'), u'number': 50.98747461471063}
----------------[sort -> limit]--------------------------
{u'_id': ObjectId('56f845fea524b4d098e0ef89'), u'number': 16.09353150244296}
{u'_id': ObjectId('56f845fea524b4d098e0ef8a'), u'number': 17.46667776660574}
{u'_id': ObjectId('56f845fea524b4d098e0ef86'), u'number': 43.25696270026136}
{u'_id': ObjectId('56f845fea524b4d098e0ef81'), u'number': 48.98052410874508}
{u'_id': ObjectId('56f845fea524b4d098e0ef82'), u'number': 50.98747461471063}

接受的答案对我不起作用,但它起作用:

last5 = db.collection.find(   {'key': "YOURKEY"},   sort=[( '_id', pymongo.DESCENDING )] ).limit(5)

在find参数的外部有limit,内部有sort。

最新更新