【问题标题】:Return the last "true" value for each group返回每个组的最后一个“真”值
【发布时间】:2018-02-22 12:45:12
【问题描述】:

我收集了其中的文档:

{
    _id: ObjectId(),
     user: ObjectId(),  
     studentName: String,
     createdAt: Date,
     isAbondoned: boolean
}

文件示例如下:

1-

{ 
    "_id" : ObjectId("56cd2d36a489a5b875902f0e"), 
    "user" : ObjectId("56c4cafabd5f92cd78ae49d4"), 
    "studentName" : "Aman", 
    "createdAt" : ISODate("2016-02-24T04:10:30.486+0000"), 
    "isAbandoned" : true
}

2-

{ 
    "_id" : ObjectId("56cd2dcda489a5b875902fcd"), 
    "user" : ObjectId("56c4cafabd5f92cd78ae49d4"), 
    "studentName" : "Aman",  
    "createdAt" : ISODate("2016-02-24T04:13:01.932+0000"), 
    "isAbandoned" : false
}

3-

{ 
    "_id" : ObjectId("56cee51503b7cb7b0eda9c4c"), 
    "user" : ObjectId("56c85244bd5f92cd78ae4bc1"), 
    "studentName" : "Rajeev",
    "createdAt" : ISODate("2016-02-25T11:27:17.281+0000"), 
    "isAbandoned" : true, 
}

现在我想找到他们的“isAbandoned”在他们最后一个“createdAt”文档中为真的学生列表。

上述示例所需的输出是:

{
    "user" : ObjectId("56c85244bd5f92cd78ae4bc1"), 
    "studentName" : "Rajeev"
}

因为 studentName "Aman" max(createdAt) 是第二个文档,而 'isAbandoned' 是假的。

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    这是一个很好的例子,需要按特定字段(createdAt)对数据进行分组,然后比较结果集匹配条件。

    1. 按学生 ID 查找最大值,
    2. 仅匹配最大条目 = createdAt 的条目
    3. 检查他们是否通过标准
    4. 重塑文档

    代码

    db.student.aggregate([{
       $group : {
           _id : "$user",
            created : {
                $max : "$createdAt"
            },
            documents : {
                $push : "$$ROOT"
            }
        }
     }, {
    $project : {
        _id : 0,
        documents : {
            $filter : {
            input : "$documents",
            as : "item",
                cond : {
                    $eq : ["$$item.createdAt", "$created"]
                }
            }
        }}
    }, {
    $match : {
        "documents.isAbandoned" : true
    }},
    { $unwind : "$documents" },
    {
    $project : {
        _id : "$documents._id",
        user : "$documents.user",
        studentName : "$documents.studentName",
        createdAt : "$documents.createdAt",
        isAbandoned : "$documents.isAbandoned",
     }}
    ])
    

    【讨论】:

    • 这行得通,但真的,真的效率不高,你真的不需要经历所有这些麻烦。
    • 如果 OP 使用旧的 MongoDB 版本,您的代码也会失败,因为 $filter 是 3.2 版中的新版本
    • @user3100115 - 未指定数据库版本 :-),所以我的假设是,顺便说一句,干净的解决方案!
    【解决方案2】:

    最好的方法是使用聚合框架。您需要通过“用户”$group 您的文档,并使用 $last 累加器运算符返回每个用户的最后一个文档,但要使其正常工作,您需要使用 $sort 聚合管道运算符进行初步排序阶段。要对文档进行排序,您需要同时考虑“createdAt”字段和“user”字段。

    管道中的最后一个阶段是$match 阶段,您只选择“isAbandoned”等于true 的最后一个文档。

    db.students.aggregate([
        { "$sort": { "user": 1, "createdAt": 1 } }, 
        { "$group": { 
            "_id": "$user", 
            "last": { "$last": "$$ROOT" }
        }}, 
        { "$match": { "last.isAbandoned": true } }
    ])
    

    返回如下内容:

    { 
        "_id" : ObjectId("56c85244bd5f92cd78ae4bc1"),
        "last" : {
            "_id" : ObjectId("56cee51503b7cb7b0eda9c4c"),
            "user" : ObjectId("56c85244bd5f92cd78ae4bc1"),
            "studentName" : "Rajeev",
            "createdAt" : ISODate("2016-02-25T11:27:17.281Z"),
            "isAbandoned" : true
        }
    }
    

    为了得到预期的结果,我们需要从verion 3.4开始使用$replaceRoot管道操作符将嵌入文档提升到顶层

    {
        $replaceRoot: { newRoot: "$last" }
    }
    

    在旧版本中,您需要使用$project 聚合管道操作来重塑我们的文档。因此,如果我们使用以下阶段扩展我们的管道:

    { 
        "$project": { 
            "_id": "$last._id", 
            "user": "$last.user", 
            "studentName": "$last.studentName", 
            "createdAt": "$last.createdAt", 
            "isAbandoned": "$last.isAbandoned"
    }}
    

    它产生预期的输出:

    {
        "_id" : ObjectId("56cee51503b7cb7b0eda9c4c"),
        "user" : ObjectId("56c85244bd5f92cd78ae4bc1"),
        "studentName" : "Rajeev",
        "createdAt" : ISODate("2016-02-25T11:27:17.281Z"),
        "isAbandoned" : true
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-27
      • 2021-07-12
      • 2021-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多