update_one mongoclient documentacion docs create python mongodb pymongo

python - mongoclient - Limitar() y ordenar() orden pymongo y mongodb



pymongo find by id (4)

Lógicamente, debería ser lo que venga primero en la tubería, pero MongoDB siempre ordena primero antes del límite.

En mi prueba, la operación de ordenación tiene prioridad independientemente de si viene antes de saltar o después. Sin embargo, me parece un comportamiento muy extraño.

Mi conjunto de datos de muestra es:

[ { "_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 } ]

Código de prueba de 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)

Resultado:

----------------[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}

A pesar de leer las respuestas de los pueblos que indican que el ordenamiento se realiza primero, la evidencia muestra algo diferente de que el límite se realiza antes del ordenamiento. ¿Hay alguna forma de forzar el orden siempre primero?

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

Si utilizo .sort().limit() o .limit().sort() , el límite tiene prioridad. Me pregunto si esto es algo que ver con pymongo ...


La documentación de mongodb indica que el método skip() controla el punto de inicio del conjunto de resultados, seguido de sort() y finaliza con el método limit() .

Esto es independientemente del orden de su código. La razón es que mongo obtiene todos los métodos para la consulta, luego ordena los métodos de salto de clasificación en ese orden exacto y luego ejecuta la consulta.


Según la documentation , independientemente de lo que ocurra primero en su cadena de comandos, sort() siempre se aplicará antes del limit() .

También puede estudiar los resultados .explain() de su consulta y observar las etapas de ejecución. Encontrará que la etapa de entrada de clasificación examina todos los filtros (en su caso, todos los documentos de la colección) y luego se aplica el límite.

Veamos un ejemplo.

Imagina que hay una base de datos foo con una colección de test tiene 6 documentos:

>>> 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}

Ahora, ejecutemos consultas con orden diferente de sort() y limit() y verifiquemos los resultados y el plan de explicación.

Ordenar y luego limitar:

>>> 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''}}

Limita y luego ordena:

>>> 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''}}

Como puede ver, en ambos casos, la clasificación se aplica primero y afecta a todos los 6 documentos y luego el límite limita los resultados a 3.

Y, los planes de ejecución son exactamente los mismos :

>>> 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

Ver también: