UDAY SINGH
UDAY SINGH

Reputation: 13

Mongoengine filter query on list embedded field based on last index

I'm using Mongoengine with Django.

I have an embedded field in my model. that is a list field of embedded documents.

import mongoengine

class OrderStatusLog(mongoengine.EmbeddedDocument):
    status_code = mongoengine.StringField()

class Order(mongoengine.DynamicDocument):
    incr_id = mongoengine.SequenceField()
    status = mongoengine.ListField(mongoengine.EmbeddedDocumentField(OrderStatusLog))

Now I want to filter the result on Order collection based on the last value in status field.

e.g. Order.objects.filter(status__last__status_code="scode")

I guess there is no such thing __last. I tried the approach mentioned in the docs http://docs.mongoengine.org/guide/querying.html#querying-lists but didn't work.

I can solve this by looping over all the documents in the collection but thats not efficient, how can we write this query efficiently.

Upvotes: 1

Views: 1965

Answers (1)

Jérôme
Jérôme

Reputation: 14704

I'm not sure MongoEngine can do that (yet). AFAIK, you'd need to use the aggregation pipeline.

In the Mongo shell, using the '$slice' and the $arrayElemAt operators:

db.order.aggregate([{ $project: {last_status: { $arrayElemAt: [{ $slice: [ "$status", -1 ] }, 0 ]} }}, {$match: {'last_status.status_code':"scode"}} ])

And in Python:

pipeline = [
    {'$project': {'last_status': { '$arrayElemAt': [{ '$slice': [ "$status", -1 ] }, 0 ]} }},
    {'$match': {'last_status.status_code':'scode'}}
]

agg_cursor = Order.objects.aggregate(*pipeline)

result = [ Order.objects.get(id=order['_id']) for order in agg_cursor ]

The trick here is that objects.aggregate provides a PyMongo cursor, not a MongoEngine cursor, so if you need MongoEngine objects, you can proceed in two steps: first filter using the aggregation framework to get the ids of matched items, then get them through a MongoEngine query.

This is what I do. From my tests, it had proven to be much more efficient than fetching everything and filtering in the python code.

If there is a simpler way, I'm interested to ear about it. Otherwise, this could be a feature request for MongoEngine. You may want to open an issue there.

Upvotes: 1

Related Questions