Cursor-based paging with a compound index in MongoDB and Python

32 Views Asked by At

The Python application I'm implementing works with the MongoDB database. I use the mongoengine module to connect and fetch data in my scripts (https://docs.mongoengine.org/).

My collection in the database has following structure:

class Item(mongoengine.Document):
    timestamp = mongoengine.DateTimeField()
    ... // the rest of the fields, the _id is added automatically

I'm trying to implement the cursor-based paging based on the compound index created with _id and timestamp. The primary reason for this is I want to order by data by the timestamp. However multiple items may have the same timestamp (year, month, day, without hours, minutes and seconds). Thus, I also need to add the _id field to the compound index. My understanding is that following list of items:

Item2, _id=1, timestamp=2024,1,2
Item1, _id=2, timestamp=2024,1,1
Item3, _id=3, timestamp=2024,1,3
Item4, _id=4, timestamp=2024,1,3

should be sorted like this:

Item4, _id=4, timestamp=2024,1,3
Item3, _id=3, timestamp=2024,1,3
Item2, _id=1, timestamp=2024,1,2
Item1, _id=2, timestamp=2024,1,1

So I tried adding a following compound index to the Item class:

meta = {
    "indexes": [
        {
            "name": "myindex",
            "fields": ["-timestamp", "_id"]
        }
    ]
}

The minus sign before timestamp, according to the documentation, means it's sorted in the descending order of timestamp field. In the case two items have the same timestamp, they should be sorted in the ascending order by the _id field.

The above does not work. So I tried to create a compound index using only one field, timestamp. This also doesn't work, no matter what order I choose (with minus before the field name or without it).

I read MongoDB documentation and they say there's a hint() command to force database to use the specified index. According to the documentation of the mongoengine module (https://docs.mongoengine.org/apireference.html?highlight=hint#mongoengine.queryset.QuerySet.hint), it also supports this command.

So I tried the following code to enforce using my index:

models.Item.objects(id=id).hint(index="myindex").limit(10)

So my expectation is the above command would fetch data, sort it according to the compound index I'm trying to enforce, use the provided id to give only 10 entries after the entry with the id provided. It also doesn't work at all.

Does mongoengine module supports compound indexes and hint() command? Is the above code correct?


EDIT

I found out that the reason I don't see the difference in my unit tests with different compound indexes is the fact that mongomock seems to not supporting compound indexes. So the only question left is how should the cursor-based pagination be implemented with a collection based on compound indexes? The mongoengine does not allow to provide hint() before querying the collection (objects().

0

There are 0 best solutions below