使用mongodb的aggregate解决变态需求

背景
现有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的各种操作命令(尤其是数组的)。好了笔记就记录这些了。

你可能感兴趣的:(技术)