基于最后一个索引的列表嵌入字段的Mongoengine过滤器查询

Mongoengine filter query on list embedded field based on last index

我在 Django 中使用 Mongoengine。

我的模型中有一个嵌入字段。那是嵌入文档的列表字段。

import mongoengine

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

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

现在我想根据 status 字段中的最后一个值过滤 Order 集合的结果。

例如Order.objects.filter(status__last__status_code="scode")

我想没有这样的东西__last。我尝试了文档中提到的方法 http://docs.mongoengine.org/guide/querying.html#querying-lists 但没有用。

我可以通过遍历集合中的所有文档来解决这个问题,但效率不高,我们如何才能高效地编写此查询。

我不确定 MongoEngine 是否可以做到这一点(目前)。据我所知,您需要使用聚合管道。

在Mongoshell中,使用'$slice' and the $arrayElemAt运算符:

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

在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 ]

这里的技巧是objects.aggregate提供了一个PyMongo游标,而不是MongoEngine游标,所以如果你需要MongoEngine个对象,你可以分两步进行: 首先使用聚合框架过滤得到匹配项的id,然后通过MongoEngine查询得到它们。

这就是我所做的。根据我的测试,它已被证明比在 python 代码中获取所有内容和过滤更有效。

如果有更简单的方法,我很想听听。否则,这可能是 MongoEngine 的功能请求。你可能想打开一个问题 there.