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

时间:2014-02-22 08:50:21

标签: mongodb mongodb-query aggregation-framework

如何使用mongodb中的条件获取数组的最后一个元素。我无法使用切片。这是我的代码

{ "1" : { "relevancy" : [  "Y" ] }, "_id" : ObjectId("530824b95f44eac1068b45c0") }
{ "1" : { "relevancy" : [  "Y",  "Y" ] }, "_id" : ObjectId("530824b95f44eac1068b45c2") }
{ "1" : { "relevancy" : [  "N" ] }, "_id" : ObjectId("530824b95f44eac1068b45c3") }
{ "1" : { "relevancy" : [  "Y",  "Y" ] }, "_id" : ObjectId("530824b95f44eac1068b45c4") }
{ "1" : { "relevancy" : [  "Y",  "N" ] }, "_id" : ObjectId("530824b95f44eac1068b45c6") }
{ "1" : { "relevancy" : [  "N" ] }, "_id" : ObjectId("530824b95f44eac1068b45c7") }
{ "1" : { "relevancy" : [  "Y",  "N" ] }, "_id" : ObjectId("530824b95f44eac1068b45c8") }

我想计算具有“Y”的行数作为数组“相关性”的最后一个元素。从上面的代码应该是3.如何做到这一点。请帮助我。

2 个答案:

答案 0 :(得分:15)

正如您现在所知,$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"。我希望你的文件看起来更像这样:

{ "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并且“然后”在$ $项目中进行任何重新塑造可能成本更低。

答案 1 :(得分:0)

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 }
])