mongoengine icon indicating copy to clipboard operation
mongoengine copied to clipboard

$geoNear is only valid as the first stage in a pipeline

Open alterEgo123 opened this issue 4 years ago • 4 comments

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

alterEgo123 avatar Mar 19 '21 10:03 alterEgo123

I'm experiencing the same problem. Did you find as solution?

robert-nash avatar Apr 17 '21 20:04 robert-nash

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

alterEgo123 avatar Apr 19 '21 10:04 alterEgo123

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)

bagerard avatar Apr 19 '21 16:04 bagerard

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': {}}}
    ])

lopsided avatar Jan 27 '22 14:01 lopsided