好问题。这里有一些事情让这并不简单。
首先要提到的是嵌套数组/列表不是标准的 django 公平,但您可以深入了解 MongoEngine 提供的 __raw__ 语法,因为这确实需要更特定于 MongoDB。
也就是说,即便如此,您想要在此处执行的过滤类型甚至超出了标准 MongoDB .find() 查询类型的范围,因为您希望匹配多个内部数组成员,然后“过滤”结果中返回的成员。
这实际上非常棘手,不仅对于嵌套数组,而且对于只能使用聚合框架才能完成的事情。尽管有任何明确的文档,但您可以通过使用类上的 ._get_collection() 方法访问集合的“原始”pymongo 驱动程序函数来使用 MongoEngine。
评论解释:
Record._get_collection().aggregate([
# Match only those documents that would meet the condition
{ "$match": {
"event_history": {
"$elemMatch": {
"$elemMatch": {"$in": [0] }
}
}
}},
# Unwind the event history array, top level
{ "$unwind": "$event_history" },
# Make a copy of the inner array
{ "$project": {
"account_id": 1,
"event_history": 1,
"status": 1,
"copy": "$event_history"
}},
# Unwind that copy
{ "$unwind": "$copy" },
# Match the numeric 0 elements only, filters non-matches
{ "$match": { "copy": 0 } },
# Group back to the original document
{ "$group": {
"_id": "$_id",
"account_id": { "$first": "$account_id" },
"event_history": { "$push": "$event_history" },
"status": { "$first": "$status" }
}}
])
如果其中有多个可能为 0 的数值,那么您需要知道它是第一个。所以多一点参与:
Record._get_collection().aggregate([
# Match only those documents that would meet the condition
{ "$match": {
"event_history": {
"$elemMatch": {
"$elemMatch": {"$in": [0] }
}
}
}},
# Unwind the event history array, top level
{ "$unwind": "$event_history" },
# Make a copy of the inner array
{ "$project": {
"account_id": 1,
"event_history": 1,
"status": 1,
"copy": "$event_history"
}},
# Unwind that copy
{ "$unwind": "$copy" },
# Group back the document keeping the "first" inner element only
{ "$group": {
"_id": {
"_id": "$_id",
"account_id": "$account_id",
"event_history": "$event_history",
"status": "$status"
},
"copy": { "$first": "$copy" }
}},
# Match only where 0 to filter
{ "$match": { "copy": 0 } },
# Group back to the original document
{ "$group": {
"_id": "$_id._id",
"account_id": { "$first": "$_id.account_id" },
"event_history": { "$push": "$_id.event_history" },
"status": { "$first": "$status" }
}}
])
以及每种情况下的结果:
{
"_id" : ObjectId("53992c7d02b8756437f81cba"),
"account_id" : ObjectId("5397929402b8751ae8a32349"),
"event_history" : [
[ 0, ISODate("2014-06-11T04:28:45.684Z") ],
[ 0, ISODate("2014-06-12T04:28:45.684Z") ]
],
"status": 1
}
所以是的,这个过程看起来有点复杂,并不像您想象的那样简单。但幸运的是,有一种方法可以访问原始收集方法并使用aggregate 来解决这个问题。