【问题标题】:Using $slice operator to get last element of array使用 $slice 运算符获取数组的最后一个元素
【发布时间】:2014-02-22 08:50:21
【问题描述】:

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

我无法使用切片。这是我的输入:

{ "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。

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    您现在应该知道,$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 并且“然后”在`$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 }
      ])
      

      【讨论】:

        猜你喜欢
        • 2022-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-29
        • 2010-10-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多