@@ -1343,6 +1343,14 @@ def from_json(self, json_data):
1343
1343
def aggregate (self , pipeline , * suppl_pipeline , ** kwargs ):
1344
1344
"""Perform an aggregate function based on your queryset params
1345
1345
1346
+ If the queryset contains a query or skip/limit/sort or if the target Document class
1347
+ uses inheritance, this method will add steps prior to the provided pipeline in an arbitrary order.
1348
+ This may affect the performance or outcome of the aggregation, so use it consciously.
1349
+
1350
+ For complex/critical pipelines, we recommended to use the aggregation framework of Pymongo directly,
1351
+ it is available through the collection object (YourDocument._collection.aggregate) and will guarantee
1352
+ that you have full control on the pipeline.
1353
+
1346
1354
:param pipeline: list of aggregation commands,
1347
1355
see: https://www.mongodb.com/docs/manual/core/aggregation-pipeline/
1348
1356
:param suppl_pipeline: unpacked list of pipeline (added to support deprecation of the old interface)
@@ -1380,7 +1388,18 @@ def aggregate(self, pipeline, *suppl_pipeline, **kwargs):
1380
1388
if self ._skip is not None :
1381
1389
initial_pipeline .append ({"$skip" : self ._skip })
1382
1390
1383
- final_pipeline = initial_pipeline + user_pipeline
1391
+ # geoNear and collStats must be the first stages in the pipeline if present
1392
+ first_step = []
1393
+ new_user_pipeline = []
1394
+ for step_step in user_pipeline :
1395
+ if "$geoNear" in step_step :
1396
+ first_step .append (step_step )
1397
+ elif "$collStats" in step_step :
1398
+ first_step .append (step_step )
1399
+ else :
1400
+ new_user_pipeline .append (step_step )
1401
+
1402
+ final_pipeline = first_step + initial_pipeline + new_user_pipeline
1384
1403
1385
1404
collection = self ._collection
1386
1405
if self ._read_preference is not None or self ._read_concern is not None :
0 commit comments