我有一系列这样的MongoDB文档:
{
"_id" : ObjectId("53992c7d02b8756437f81cba"),
"account_id" : ObjectId("5397929402b8751ae8a32349"),
"event_history" : [
[ 0, ISODate("2014-06-12T04:28:45.684Z") ],
[ 0, ISODate("2014-06-11T04:28:45.684Z") ],
[ 1, ISODate("2014-05-12T04:28:45.684Z") ]
],
"status" : 1
}
是否有可能返回具有0
作为第一个元素的event_history
's(在MongoEngine)?
我想要得到这个:
[ 0, ISODate("2014-06-12T04:28:45.684Z") ],
[ 0, ISODate("2014-06-11T04:28:45.684Z") ],
这是我尝试的查询,但它不起作用:
Record.objects(id=ObjectId("53992c7d02b8756437f81cba"), event_history__in=[0])
问得好。这里有一些事情使它不简单。
首先要提到的是嵌套数组/列表的事情不是标准的django公平,但你可以潜入__raw__
语法提供的MongoEngine,因为这确实需要更多的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
}
所以,这个过程看起来有点复杂,并不像你想象的那么简单。但幸运的是,有一种方法可以访问原始集合方法并使用聚合来解决这个问题。