现在您已经意识到,$slice仅用于投影,以限制返回结果中的数组元素。 因此,您将被迫使用来自find()的结果编程处理列表。
更好的方法是使用aggregate。 但首先让我们考虑如何使用$slice:
> db.collection.find({},{ relevancy: {$slice: -1} })
{ "_id" : ObjectId("530824b95f44eac1068b45c0"), "relevancy" : [ "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c2"), "relevancy" : [ "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c3"), "relevancy" : [ "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c4"), "relevancy" : [ "Y" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c6"), "relevancy" : [ "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c7"), "relevancy" : [ "N" ] }
{ "_id" : ObjectId("530824b95f44eac1068b45c8"), "relevancy" : [ "N" ] }
所以你得到了最后一个数组元素,但是由于无法“匹配”最后一个元素的值,因此你被困在循环结果中。你可能会选择在代码中完成这个任务。
现在让我们来看一下“聚合”:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$unwind": "$relevancy" },
{ "$group": { "_id": "$_id", "relevancy": { "$last": "$relevancy" } }},
{ "$match": { "relevancy": "Y" }},
{ "$sort": { "_id": 1 } }
])
即使这是您第一次使用aggregate(),我也鼓励您学习它。它可能是您最有用的问题解决工具,对我来说肯定如此。如果您正在学习,请一次只执行每个步骤。
另外,我不确定您的文档格式,所有的1:{...}子文档符号似乎都是错误的,但您应该清理它或调整上面的代码以引用“1.relevancy”而不是“1:{...}”。我希望您的文档实际上看起来更像这样:
{ "relevancy" : [ "Y" ] , "_id" : ObjectId("530824b95f44eac1068b45c0") }
{ "relevancy" : [ "Y", "Y" ] , "_id" : ObjectId("530824b95f44eac1068b45c2") }
{ "relevancy" : [ "N" ], "_id" : ObjectId("530824b95f44eac1068b45c3") }
{ "relevancy" : [ "Y", "Y" ], "_id" : ObjectId("530824b95f44eac1068b45c4") }
{ "relevancy" : [ "Y", "N" ], "_id" : ObjectId("530824b95f44eac1068b45c6") }
{ "relevancy" : [ "N" ], "_id" : ObjectId("530824b95f44eac1068b45c7") }
{ "relevancy" : [ "Y", "N" ], "_id" : ObjectId("530824b95f44eac1068b45c8") }
MongoDB 3.2.x及以上版本
当然,MongoDB 3.2引入了一个“聚合”运算符$slice
和一个更好的$arrayElemAt
运算符,它消除了任何$unwind
和$group
处理的需要。在初始的$match
查询之后,您只需使用$redact
进行“逻辑匹配”:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
这将检查数组的最后一个元素,以决定是否从返回的结果中
$$KEEP
或
$$PRUNE
文档。如果您仍想要“投影”,则可以添加
$slice
:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$arrayElemAt": [ "$relevancy", -1 ], "Y" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } }
])
或者另一种方法:
db.collection.aggregate([
{ "$match": { "relevancy": "Y" } },
{ "$project": { "relevancy": { "$slice": [ "$relevancy", -1 ] } } },
{ "$match": { "relevancy": "Y" } }
])
但是先进行$redact
操作,然后在`$project`中进行任何重新塑形可能会更加节省成本。