查找某个主题中失败的学生的数量和百分比

时间:2017-02-13 15:03:55

标签: mongodb mongodb-query aggregation-framework

我是MongoDB的新手并且学习编写mongodb查询。我需要以下问题的帮助:

输入数据是一个集合student,有五个记录:

[
    {
        "_id":0,
        "name":"Maxy",
        "results":[
            {
                "subject":"maths",
                "score":1.46
            },
            {
                "subject":"english",
                "score":11.78
            },
            {
                "subject":"history",
                "score":6.67
            }
        ]
    },
    {
        "_id":1,
        "name":"Nancy",
        "results":[
            {
                "subject":"maths",
                "score":60.06
            },
            {
                "subject":"english",
                "score":52.79
            },
            {
                "subject":"history",
                "score":71.76
            }
        ]
    },
    {
        "_id":2,
        "name":"Peter",
        "results":[
            {
                "subject":"maths",
                "score":27.03
            },
            {
                "subject":"english",
                "score":6.30
            },
            {
                "subject":"history",
                "score":20.18
            }
        ]
    },
    {
        "_id":3,
        "name":"Harry",
        "results":[
            {
                "subject":"maths",
                "score":71.64
            },
            {
                "subject":"english",
                "score":24.80
            },
            {
                "subject":"history",
                "score":1.69
            }
        ]
    },
    {
        "_id":4,
        "name":"Paxy",
        "results":[
            {
                "subject":"maths",
                "score":28.68
            },
            {
                "subject":"english",
                "score":90.29
            },
            {
                "subject":"history",
                "score":34.41
            }
        ]
    }
]

我需要得到数学失败的学生数量"主题,通过分数为35.

我尝试了以下方法:

// Will give count of students who failed in subject:maths
var count = db.student.find({
    results : {
        $elemMatch: {
            subject: "maths",
            score: { $lt: 35 } 
        } 
    } 
}).count() // ==>> 3

// Total students
var total = db.student.count() // ==>> 5

// Percentage
var percentage = count*100/total // ==>> 3*100/5=60%

是否可以计算学生的数量和百分比在数学"主题在一个查询中?

2 个答案:

答案 0 :(得分:3)

这是在集合上使用聚合执行的另一个选项:

db.student.aggregate([
    {$unwind:"$results"},
    {$match: {"results.subject": "maths"}},
    {$group: {
        _id: null,
        totalCount: {$sum:1},
        failCount: {$sum: { "$cond": [{ "$lt": ["$results.score", 35 ] }, 1, 0 ] }}}},
    {$project: {
        _id : 0,
        totalCount : 1,
        failCount : 1,
        failPercent: {
            $multiply: [ { $divide: ["$failCount", "$totalCount"] }, 100 ]
        }
    }}
])

仅当结果包含数学结果时,学生记录才被视为总计;一名学生希望得到一个数学结果。

管道运营商:
放松 - >获得每个主题的单独行
匹配 - >仅考虑数学结果
组 - >运行分组以获得总计数;使用条件来识别失败的计数
项目 - >项目所需的元素和结果输出百分比

{
    "totalCount" : 5,
    "failCount" : 3,
    "failPercent" : 60
}

答案 1 :(得分:0)

您需要使用MongoDB的聚合框架为单个查询运行聚合操作。考虑运行以下管道以获得所需的结果:

db.student.aggregate([
    {
        "$project": {
            "maths_result": {
                "$arrayElemAt": [
                    {
                        "$filter": {
                            "input": "$results",
                            "as": "res",
                            "cond": {
                                "$eq": ["$$res.subject", "maths"]
                            }
                        }
                    },
                    0
                ]
            }
        }
    },
    {
        "$project": {
            "maths_fail": { "$lt": ["$maths_result.score", 35 ] }
        }
    },
    {
        "$group": {
            "_id": null,
            "total": { "$sum": 1 },
            "fail_count": { "$sum": { "$cond": ["$maths_fail", 1, 0 ] } }
        }
    },
    {
        "$project": {
            "percentage_maths_fail": {
                "$multiply": [
                    { "$divide": ["$fail_count", "$total"] },
                    100
                ]
            }
        }
    }
])

管道说明

执行管道时,MongoDB将运营商互相管道。 "管"这里采用Linux的含义:运算符的输出成为以下运算符的输入。每个运算符的结果是一个新的文档集合。所以Mongo按如下方式执行上述管道:

collection | $project | $project | $group | $project => result

第一个管道步骤 $project ,与SQL中的SELECT语句非常相似,在这种情况下,它用于创建一个具有单个元素的新字段results数组。这可以通过 $arrayElemAt 和$ filter运算符实现。 $filter 运算符表达式将返回一个与主题字段为" maths"并且 $arrayElemAt 返回数组中的第一个元素,类似于展平它。

因此,仅使用此步骤运行管道将产生结果:

db.student.aggregate([
    {
        "$project": {
            "maths_result": {
                "$arrayElemAt": [
                    {
                        "$filter": {
                            "input": "$results",
                            "as": "res",
                            "cond": {
                                "$eq": ["$$res.subject", "maths"]
                            }
                        }
                    },
                    0
                ]
            }
        }
    }
])

示例输出

/* 1 */
{
    "_id" : 0,
    "maths_result" : {
        "subject" : "maths",
        "score" : 1.46
    }
}

/* 2 */
{
    "_id" : 1,
    "maths_result" : {
        "subject" : "maths",
        "score" : 60.06
    }
}

/* 3 */
{
    "_id" : 2,
    "maths_result" : {
        "subject" : "maths",
        "score" : 27.03
    }
}

/* 4 */
{
    "_id" : 3,
    "maths_result" : {
        "subject" : "maths",
        "score" : 71.64
    }
}

/* 5 */
{
    "_id" : 4,
    "maths_result" : {
        "subject" : "maths",
        "score" : 28.68
    }
}

下一个 $project 运算符的第二步将重构上述字段,以便为失败条件返回true或false:

db.student.aggregate([
    {
        "$project": {
            "maths_result": {
                "$arrayElemAt": [
                    {
                        "$filter": {
                            "input": "$results",
                            "as": "res",
                            "cond": {
                                "$eq": ["$$res.subject", "maths"]
                            }
                        }
                    },
                    0
                ]
            }
        }
    },
    {
        "$project": {
            "maths_fail": { "$lt": ["$maths_result.score", 35 ] }
        }
    }       
])

示例输出

/* 1 */
{
    "_id" : 0,
    "maths_fail" : true
}

/* 2 */
{
    "_id" : 1,
    "maths_fail" : false
}

/* 3 */
{
    "_id" : 2,
    "maths_fail" : true
}

/* 4 */
{
    "_id" : 3,
    "maths_fail" : false
}

/* 5 */
{
    "_id" : 4,
    "maths_fail" : true
}

第3步 $group 将所有文档整体分组以汇总计数。总文档计数由表达式"total": { "$sum": 1 }导出,而条件总和

"$sum": { "$cond": ["$maths_fail", 1, 0 ] } 

将为您提供失败的总数:

db.student.aggregate([
    {
        "$project": {
            "maths_result": {
                "$arrayElemAt": [
                    {
                        "$filter": {
                            "input": "$results",
                            "as": "res",
                            "cond": {
                                "$eq": ["$$res.subject", "maths"]
                            }
                        }
                    },
                    0
                ]
            }
        }
    },
    {
        "$project": {
            "maths_fail": { "$lt": ["$maths_result.score", 35 ] }
        }
    },
    {
        "$group": {
            "_id": null,
            "total": { "$sum": 1 },
            "fail_count": { "$sum": { "$cond": ["$maths_fail", 1, 0 ] } }
        }
    }
])

示例输出

/* 1 */
{
    "_id" : null,
    "total" : 5,
    "fail_count" : 3
}

最后的渠道会使用arithmetic operators $divide $multiply 为您提供百分比:

{
    "$project": {
        "percentage_maths_fail": {
            "$multiply": [
                { "$divide": ["$fail_count", "$total"] },
                100
            ]
        }
    }
}

最终输出

/* 1 */
{
    "_id" : null,
    "percentage_maths_fail" : 60
}