查询最后一个数组值

时间:2017-06-22 05:34:08

标签: mongodb mongodb-query aggregation-framework

db.chat.find().pretty().limit(3)
{
    "_id" : ObjectId("593921425ccc8150f35e7662"),
    "user1" : 1,
    "user2" : 2,
    "messages" : [
        {
            "capty" : 'A',
            "body" : "hiii 0"
        },
        {
            "capty" : 'B',
            "body" : "hiii 1"
        },
        {
            "capty" : 'A',
            "body" : "hiii 2"
        }
    ]
}
{
    "_id" : ObjectId("593921425ccc8150f35e7663"),
    "user1" : 1,
    "user2" : 3,
    "messages" : [
        {
            "capty" : 'A',
            "body" : "hiii 0"
        },
        {
            "capty" : 'A',
            "body" : "hiii 1"
        },
        {
            "capty" : 'B',
            "body" : "hiii 23"
        }
    ]
}
{
    "_id" : ObjectId("593921425ccc8150f35e7664"),
    "user1" : 1,
    "user2" : 4,
    "messages" : [
        {
            "capty" : 'A',
            "body" : "hiii 0"
        },
        {
            "capty" : 'B',
            "body" : "hiii 1"
        },
        {
            "capty" : 'B',
            "body" : "hiii 24"
        }
    ]
}

我不是要弄清楚会给出user2列表的查询,以及user1 = 1的主体和消息的最后一个cap =' B'。即输出应该是最后2行。

即可取的输出。

user2:3, "body" : "hiii 23"
user2:4, "body" : "hiii 24"

1 个答案:

答案 0 :(得分:0)

这里的主要内容是聚合$slice以从数组中获取最后一个元素

db.chat.aggregate([
 { "$match": { "user1": 1,  "messages.capty": "B" } },
 { "$redact": {
   "$cond": {
     "if": { 
       "$eq": [ { "$slice": [ "$messages.capty", -1 ] }, ["B"] ]  
     },
     "then": "$$KEEP",
     "else": "$$PRUNE"
   }
 }},
 { "$project": {
   "user2": 1,
   "body": {
     "$arrayElemAt": [
       { "$map": {
         "input": { 
           "$filter": {
             "input": { "$slice": [ "$messages",-1 ] },
             "as": "m",
             "cond": { "$eq": [ "$$m.capty", "B" ] }
           }
         },
         "as": "m",
         "in": "$$m.body"
       }},
       0
     ]
   }
 }}
])

我实际上是"额外的安全"在$project阶段$filter,但基本相同。

首先查询选择文件,我们实际上不能在这一点上说"只有"匹配数组的最后一个元素,但我们想要过滤那些在数组上没有条件的文档。

$redact实际上是关注" last"数组条目并测试字段的值。我们可以通过$messages.capty来回显示数组中的字段,它只返回这些项的数组。如果您想获取最后一个值,那么我们接着$slice甚至$arrayElemAt,作为-1的索引。

此时我们只是"过滤" "文件"哪个与条件不符。最后的$project阶段获取数组的最后一个元素,检查它是否与条件匹配(它应该是早期阶段),提取"body"的值并将单个数组内容转换为平面值。

你可以选择放弃"谨慎"并且只是抓住最后一个数组元素,因为$redact应该完成它的工作:

db.chat.aggregate([
 { "$match": { "user1": 1,  "messages.capty": "B" } },
 { "$redact": {
   "$cond": {
     "if": { 
       "$eq": [ { "$arrayElemAt": [ "$messages.capty", -1 ] }, "B" ]  
     },
     "then": "$$KEEP",
     "else": "$$PRUNE"
   }
 }},
 { "$project": {
   "user2": 1,
   "body": {
     "$arrayElemAt": [ "$messages.body", -1 ]
   }
 }}
])

整个事情真的分解为"将可能的文档与查询匹配"然后"用$slice$arrayElemAt"比较并提取最后一个元素。

结果是:

{
        "_id" : ObjectId("593921425ccc8150f35e7663"),
        "user2" : 3,
        "body" : "hiii 23"
}
{
        "_id" : ObjectId("593921425ccc8150f35e7664"),
        "user2" : 4,
        "body" : "hiii 24"
}