$geoNear is only valid as the first stage in a pipeline
Hello,
Running the following example which uses $geoNear in an aggregation pipeline returns a $geoNear is only valid as the first stage in a pipeline error.
from mongoengine import *
def aggregate():
connect()
class BaseClass(Document):
meta = {'allow_inheritance': True}
class Aggr(BaseClass):
name = StringField()
c = PointField()
Aggr.drop_collection()
Aggr(name="X", c=[10.634584, 35.8245029]).save()
Aggr(name="Y", c=[10.634584, 35.8245029]).save()
pipeline = [
{
"$geoNear": {
"near": {"type": "Point", "coordinates": [10.634584, 35.8245029]},
"distanceField": "c",
"spherical": True,
}
}
]
list(Aggr.objects.aggregate(*pipeline))
aggregate()
Using:
mongoengine: 0.17.0
MongoDB server version: 4.4.0
I'm experiencing the same problem. Did you find as solution?
@robert-nash I had to change all my documents to inherit from Document class instead of BaseClass(Document). Another thing you can do it, is to edit mongoengine's mongoengine/queryset/base.py
Edit this line and add initial_pipeline only if there's not geoNear stage in the pipeline. pipeline = initial_pipeline + list(pipeline)
I'm not against fixing this in MongoEngine itself but I have limited experience with aggregation pipelines. Can there be side effects (like different outputs) if we change the order of the pipeline steps ? or is it just potentially impacting performances?
I guess what you want is something like
geonear_step = ...
rest_of_pipeline = ...
pipeline = initial_pipeline + rest_of_pipeline
if geonear_step:
pipeline.insert(0, geonear_step)
I've come across the same problem with a $collStats query on a document with inheritance. Same error: $collStats is only valid as the first stage in a pipeline and same cause -- initial pipeline being added.
I've hacked a fix by setting the objects' _cls_query to None right before running the aggregation query. This prevents the initial pipeline being added. I wouldn't recommend doing anything else with the instance after this though as it will probably break things! But for a simple query like mine it seems to get around the problem without having to edit or patch the package files.
Aggr.objects._cls_query = None
cursor = Aggr.objects.aggregate([
{'$collStats': {'count': {}}}
])