MongoEngine / mongoengine

A Python Object-Document-Mapper for working with MongoDB
http://mongoengine.org
MIT License
4.23k stars 1.23k forks source link

Empty (but not None) ordering object interrupting ordering of queryset #2498

Closed wsidl closed 3 years ago

wsidl commented 3 years ago

https://github.com/MongoEngine/mongoengine/blob/f0fad6df19bee4917fb01fa98924baa6ffeb5031/mongoengine/queryset/base.py#L1664

Local instance shows the values for self._ordering is an empty list, not None. This fails the condition not allowing for the default ordering provided by the document.

        print(self._ordering)
        print(self._document._meta["ordering"])

gives

[]
['-timestamp']

as the empty list is not None, it does not allow the condition to continue with Document ordering set in it's meta mapping.

wsidl commented 3 years ago

The goal is to provide the list of documents provided by the query to return objects in order of the latest timestamp. Current setup:

# models.py
import mongoengine as mg
import mongoengine.fields as mgf

class MyModel(mg.Document):
    meta = {
        "collection": "my_collection",
        "indexes": ["timestamp", "field_a", "field_b"],
        "ordering": ["-timestamp"]
    }
    field_a = mgf.IntField(required=True)
    field_b = mgf.StringField(required=True)
    field_c = mgf.StringField()
    timestamp = mgf.DateTimeField(required=True)
# schemas.py
import models
import graphene
from graphene_mongo import MongoengineObjectType

class MySchema(MongoengineObjectType):
    class Meta:
        interfaces = (graphene.relay.Node, )
        model = models.MyModel
        filter_fields = {
            "field_b": ["icontains", "istartswith", "iendswith"]
        }

With the current implementation when _cursor() is called, self._ordering is an empty list. It's also very possible this may be an issue in graphene_mongo, but was only able to get the expected results via the Mongoengine module.

bagerard commented 3 years ago

Looking at that part of the comment around that code

       # Apply ordering to the cursor.
        # XXX self._ordering can be equal to:
        # * None if we didn't explicitly call order_by on this queryset.
        # * A list of PyMongo-style sorting tuples.
        # * An empty list if we explicitly called order_by() without any    <----
        #   arguments. This indicates that we want to clear the default
        #   ordering.
        if self._ordering:
            # explicit ordering
            self._cursor_obj.sort(self._ordering)
        elif self._ordering is None and self._document._meta["ordering"]:
            # default ordering
            order = self._get_order_by(self._document._meta["ordering"])
            self._cursor_obj.sort(order)

It sounds like this is a feature, rather than a bug.

I'm not familiar with graphene_mongo but it may be that its calling .order_by() without argument at some point, which clears the default ordering. Open a ticket on graphene_mongo

wsidl commented 3 years ago

I'll look into that. I'll be sure to reference this bug as part of that issue.

Thanks