使用mongodb的aggregate解决变态需求

来源:互联网 发布:mysql affected rows 编辑:程序博客网 时间:2024/05/22 00:30

背景
现有1000条学生记录,结构如下:

{    name:String,//名称    clazz:{type:ObjectId,ref:"classes"},//班级id    status:Number,//状态 1在校 2离校    marks:[Number],//标记 1迟到 2早退 3请假    age:Number//年龄}

需求
要求统计1000个学生的所在班级列表,列表内容如下(模拟数据,不要在意统计的合理不合理):

班级名称 在校人数 离校人数 没有迟到标记的在校人数 没有迟到标记的在校学生的平均年龄

实现代码:

db.getCollection('students').aggregate([{    $group: {//班级分组拿到班级id和班级内的学员信息        _id: "$clazz",        stus: {            $push: "$$ROOT"        }    }}, {    $project: {        _id: 1,        stus: 1,        out_num: {//计算离校人员数量            $size: {                $filter: {                    input: "$stus",                    as: "stu",                    cond: { $eq: ["$$stu.status", 2] }                }            }        },        in_num: {//计算在校人员数量            $size: {                $filter: {                    input: "$stus",                    as: "stu",                    cond: { $eq: ["$$stu.status", 1] }                }            }        },        in_no_1: {//计算 在校并且没有迟到标记的学员列表            $filter: {                input: "$stus",                as: "stu",                cond: { $and: [{ $eq: ["$$stu.status", 1] }, { $eq: [{ $indexOfArray: ["$$stu.marks", 1] }, -1] }] }            }        },    }}, {    $project: {        _id: 1,        out_num: 1,        in_num: 1,        in_no_1: 1,        in_nu_1_num: { $size: "$in_no_1" },//计算在校并且没有迟到标记的学员数量        avg: {//计算在校并且没有迟到标记的学员的平均年龄            $cond: {                if: { $eq: [{ $size: "$in_no_1" }, 0] },//如果班级内没有符合条件的学生则年龄记为0                then: 0,                else: {//班级内有符合条件的学生,计算学生年龄总和并除以学生数量                    $divide: [{                        $reduce: {                            input: "$in_no_1",                            initialValue: 0,                            in : { $add: ['$$value', "$$this.age"] }                        }                    }, {                        $size: "$in_no_1"                    }]                }            }        }    }}, {    $lookup: {//关联查询班级信息,关联信息返回为数组        from: "classes",        localField: "_id",        foreignField: "_id",        as: "clazz"    }}, {    $unwind: '$clazz'//拆分班级返回信息数组}, {    $project: {//整理最后的数据        _id: 1,        out_num: 1,        in_num: 1,        avg: 1,        in_nu_1_num: 1,        name: '$clazz.name'    }}])

代码就这些,需要看的是aggregate的各种操作命令(尤其是数组的)。好了笔记就记录这些了。

原创粉丝点击