使用$slice运算符获取数组的最后一个元素

13

如何在mongodb中根据条件获取数组的最后一个元素?

我无法使用slice。以下是我的输入:

{ "1" : { "relevancy" : [  "Y" ] } }
{ "1" : { "relevancy" : [  "Y",  "Y" ] } }
{ "1" : { "relevancy" : [  "N" ] } }
{ "1" : { "relevancy" : [  "Y",  "Y" ] } }
{ "1" : { "relevancy" : [  "Y",  "N" ] } }
{ "1" : { "relevancy" : [  "N" ] } }
{ "1" : { "relevancy" : [  "Y",  "N" ] } }
我想要计算“相关性”数组中最后一个元素为“Y”的行数。
针对上述输入记录,答案应该是3。
2个回答

17

现在您已经意识到,$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 things so we get rid of the documents that will never match, but it will
    // still keep some of course since they are arrays, that *may* contain "N"
    { "$match": { "relevancy": "Y" } },

    // De-normalizes the array
    { "$unwind": "$relevancy" },

    // The order of the array is retained, so just look for the $last by _id
    { "$group": { "_id": "$_id", "relevancy": { "$last": "$relevancy" } }},

    // Match only the records with the results you want
    { "$match": { "relevancy": "Y" }},

    // Oh, and maintain the original _id order [ funny thing about $last ]
    { "$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`中进行任何重新塑形可能会更加节省成本。


2
从Mongo 4.4开始,聚合运算符$last可用于访问数组的最后一个元素:
// { "1": { "relevancy": ["Y"] } }
// { "1": { "relevancy": ["Y", "Y"] } }
// { "1": { "relevancy": ["N"] } }
// { "1": { "relevancy": ["Y", "Y"] } }
// { "1": { "relevancy": ["Y", "N"] } }
// { "1": { "relevancy": ["N"] } }
// { "1": { "relevancy": ["Y", "N"] } }
db.collection.aggregate([
  { $project: { last: { $last: "$1.relevancy" } } },
  // { "last": "Y" }
  // { "last": "Y" }
  // { "last": "N" }
  // { "last": "Y" }
  // { "last": "N" }
  // { "last": "N" }
  // { "last": "N" }
  { $match: { "last": "Y" } },
  // { "last": "Y" }
  // { "last": "Y" }
  // { "last": "Y" }
  { $count: "result" }
  // { "result" : 3 }
])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接