MongoDB查詢(xún)實(shí)現(xiàn) 行級(jí)別的聚合函數(shù)


title: MongoDB 實(shí)現(xiàn)行級(jí)別的聚合函數(shù)(類(lèi)似于Oracle的開(kāi)窗函數(shù))
tags: []
notebook: test note book


場(chǎng)景: 顯示每個(gè)班級(jí)每個(gè)人每科的分?jǐn)?shù),班級(jí)的平均分,班級(jí)排名等聚合列

row data 為每個(gè)人的名字,年級(jí),科目,分?jǐn)?shù).要求統(tǒng)計(jì)出每個(gè)人的成績(jī)總分,單科成績(jī)排名,總分成績(jī)排名,班級(jí)成績(jī)排名.并且顯示在每一行上.

測(cè)試數(shù)據(jù)

db.score.insert({ "_id":"1", "name":"test1", "subject":"語(yǔ)文", "score":70, "class":"四年級(jí)"});
db.score.insert({ "_id":"2", "name":"test2", "subject":"語(yǔ)文", "score":80, "class":"四年級(jí)"});
db.score.insert({ "_id":"3", "name":"test3", "subject":"語(yǔ)文", "score":59, "class":"四年級(jí)"});
db.score.insert({ "_id":"4", "name":"test4", "subject":"語(yǔ)文", "score":78, "class":"五年級(jí)"});
db.score.insert({ "_id":"5", "name":"test5", "subject":"語(yǔ)文", "score":99, "class":"五年級(jí)"});
db.score.insert({ "_id":"6", "name":"test6", "subject":"語(yǔ)文", "score":67, "class":"五年級(jí)"});
db.score.insert({ "_id":"7", "name":"test1", "subject":"數(shù)學(xué)", "score":56, "class":"四年級(jí)"});
db.score.insert({ "_id":"8", "name":"test2", "subject":"數(shù)學(xué)", "score":78, "class":"四年級(jí)"});
db.score.insert({ "_id":"9", "name":"test3", "subject":"數(shù)學(xué)", "score":57, "class":"四年級(jí)"});
db.score.insert({ "_id":"10", "name":"test4", "subject":"數(shù)學(xué)", "score":88, "class":"五年級(jí)"});
db.score.insert({ "_id":"11", "name":"test5", "subject":"數(shù)學(xué)", "score":69, "class":"五年級(jí)"});
db.score.insert({ "_id":"12", "name":"test6", "subject":"數(shù)學(xué)", "score":47, "class":"五年級(jí)"});
db.score.insert({ "_id":"13", "name":"test1", "subject":"英語(yǔ)", "score":79, "class":"四年級(jí)"});
db.score.insert({ "_id":"14", "name":"test2", "subject":"英語(yǔ)", "score":66, "class":"四年級(jí)"});
db.score.insert({ "_id":"15", "name":"test3", "subject":"英語(yǔ)", "score":88, "class":"四年級(jí)"});
db.score.insert({ "_id":"16", "name":"test4", "subject":"英語(yǔ)", "score":97, "class":"五年級(jí)"});
db.score.insert({ "_id":"17", "name":"test5", "subject":"英語(yǔ)", "score":68, "class":"五年級(jí)"});
db.score.insert({ "_id":"18", "name":"test6", "subject":"英語(yǔ)", "score":77, "class":"五年級(jí)"});

先給出查詢(xún)語(yǔ)句,再一步步分析

db.score.aggregate([
    {
        $sort:{
            score:-1
        }
    },
    {
        $group:{
            _id:{
                subject:"$subject",
                class:"$class"
            },
            avgScore:{
                $avg:"$score"
            },
            sumScore:{
                $sum:"$score"
            },
            rowData:{
                $push:"$$ROOT"
            }
        }
    },
    {
        $unwind:{
            path:"$rowData",
            preserveNullAndEmptyArrays:true,
            includeArrayIndex:"rangIndex"
        }
    },  
    {
        $group:{
            _id:"$rowData.name",
            totalScore:{
                $sum:"$rowData.score"
            },
            rowData:{
                $push:"$$ROOT"
            }
        }
    },
    {
        $unwind:{
            path:"$rowData",
            preserveNullAndEmptyArrays:true,
        }
    },
    {
        $project:{
            _id:0,
            姓名:"$_id",
            年級(jí):"$rowData._id.class",
            科目:"$rowData._id.subject",
            成績(jī):"$rowData.rowData.score",
            總分:"$totalScore",
            年級(jí)科目成績(jī)排名:{$add:["$rowData.rangIndex",1]},
            年級(jí)科目平均分:"$rowData.avgScore",
            年級(jí)科目總分:"$rowData.sumScore"
        }
    }
]);

查詢(xún)結(jié)果

姓名 年級(jí) 科目 成績(jī) 總分 科目層級(jí)年級(jí)排名 年級(jí)科目平均分 年級(jí)科目總分
test5 五年級(jí) 數(shù)學(xué) 69 236 2 68 204
test5 五年級(jí) 語(yǔ)文 99 236 1 81 244
test5 五年級(jí) 英語(yǔ) 68 236 3 80 242
test6 五年級(jí) 數(shù)學(xué) 47 191 3 68 204
test6 五年級(jí) 語(yǔ)文 67 191 3 81 244
test6 五年級(jí) 英語(yǔ) 77 191 2 80 242
test4 五年級(jí) 數(shù)學(xué) 88 263 1 68 204
test4 五年級(jí) 語(yǔ)文 78 263 2 81 244
test4 五年級(jí) 英語(yǔ) 97 263 1 80 242
test1 四年級(jí) 數(shù)學(xué) 56 205 3 63 191
test1 四年級(jí) 語(yǔ)文 70 205 2 69 209
test1 四年級(jí) 英語(yǔ) 79 205 2 77 233
test3 四年級(jí) 數(shù)學(xué) 57 204 2 63 191
test3 四年級(jí) 語(yǔ)文 59 204 3 69 209
test3 四年級(jí) 英語(yǔ) 88 204 1 77 233
test2 四年級(jí) 數(shù)學(xué) 78 224 1 63 191
test2 四年級(jí) 語(yǔ)文 80 224 1 69 209
test2 四年級(jí) 英語(yǔ) 66 224 3 77 233

查詢(xún)語(yǔ)句分析

    {
        $sort:{
            score:-1
        }
    },

先按分?jǐn)?shù)從高到低講所有數(shù)據(jù)排序,目的是為了之后方便算出科目層級(jí)年級(jí)排名.


    {
        $group:{
            _id:{
                subject:"$subject",
                class:"$class"
            },
            avgScore:{
                $avg:"$score"
            },
            sumScore:{
                $sum:"$score"
            },
            rowData:{
                $push:"$$ROOT"
            }
        }
    },

  • 按年級(jí)和科目進(jìn)行分組,目的是算出科目平均分和科目的總分.此處的rowData用了$group函數(shù)的子函數(shù)$push,$push的作用是進(jìn)行分組時(shí),將原始數(shù)據(jù)塞入到一個(gè)數(shù)組里面,有點(diǎn)類(lèi)似于$unwind的反過(guò)來(lái)的用法.因?yàn)槲覀冎筮€是要用到row level 的數(shù)據(jù).

  • "$$ROOT" 的意思是將整個(gè)目錄push到數(shù)組里面, 這里也可以push自己想要的fields

    rowData:{
        $push:{
            name:"$name",
            score:"$score"
        }
    }

    {
        $unwind:{
            path:"$rowData",
            preserveNullAndEmptyArrays:true,
            includeArrayIndex:"rangIndex"
        }
    },  

unwind的作用是將數(shù)組解壓,那么我們即又可以得到row level 的數(shù)據(jù)了,此時(shí)每一行的數(shù)據(jù)也包含sumScore,avgScoure 屬性了.而這里的 includeArrayIndex屬性的意思是在unwind時(shí),給每條記錄加一個(gè)rangIndex屬性,屬性的內(nèi)容是行號(hào),有點(diǎn)類(lèi)似于oracle的rownumber.要注意的是這里的includeArrayIndex是每個(gè)組的行號(hào),也就是換一組就又會(huì)從0開(kāi)始,而且是默認(rèn)排序,到這里也就會(huì)明白為什么我會(huì)在最前面加一個(gè)$sort函數(shù)先排好序.


    {
        $group:{
            _id:"$rowData.name",
            totalScore:{
                $sum:"$rowData.score"
            },
            rowData:{
                $push:"$$ROOT"
            }
        }
    },
    {
        $unwind:{
            path:"$rowData",
            preserveNullAndEmptyArrays:true,
        }
    },

和上面的group類(lèi)似,此處作用是算出個(gè)人的總成績(jī),再u(mài)nwind 出row level data


    {
        $project:{
            _id:0,
            姓名:"$_id",
            年級(jí):"$rowData._id.class",
            科目:"$rowData._id.subject",
            成績(jī):"$rowData.rowData.score",
            總分:"$totalScore",
            年級(jí)科目成績(jī)排名:{$add:["$rowData.rangIndex",1]},
            年級(jí)科目平均分:"$rowData.avgScore",
            年級(jí)科目總分:"$rowData.sumScore"
        }
    }

顯示出需要的結(jié)果.這里的年級(jí)科目成績(jī)排名稍微處理了一下,每個(gè)結(jié)果都+1,因?yàn)閕ndex是從0開(kāi)始的


我們還可以計(jì)算

  • 成績(jī)類(lèi)別 不及格/及格/良好/優(yōu)秀
  • 班級(jí)人數(shù)統(tǒng)計(jì)
  • 總成績(jī)排名
  • 結(jié)果按年級(jí),科目,年級(jí)科目成績(jī)排名升序排名

有興趣的可以根據(jù)測(cè)試數(shù)據(jù)進(jìn)行查詢(xún)語(yǔ)句的改寫(xiě),算是鞏固練習(xí).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,706評(píng)論 18 399
  • 分析函數(shù),也稱(chēng)為窗口函數(shù),通常被認(rèn)為僅對(duì)數(shù)據(jù)倉(cāng)庫(kù)SQL有用。使用分析函數(shù)的查詢(xún),基于對(duì)數(shù)據(jù)行的分組來(lái)計(jì)算總量值。與...
    貓貓_tomluo閱讀 3,471評(píng)論 3 18
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 4,012評(píng)論 0 11
  • ?我們首先看到的是1級(jí)競(jìng)技場(chǎng),也就是最初級(jí)的水平。在這個(gè)層級(jí)當(dāng)中的需求呢,通常是一些最基本的統(tǒng)計(jì)需求,例如求和、統(tǒng)...
    碧雪丹蓉閱讀 3,669評(píng)論 2 16
  • 到了1996年,還怎么寫(xiě)二戰(zhàn)時(shí)期德國(guó)人對(duì)周邊國(guó)家的傷害?挪威,在我打算閱讀挪威作家佩爾·帕特森的《去往西伯利亞》時(shí)...
    吳玫閱讀 1,029評(píng)論 0 2

友情鏈接更多精彩內(nèi)容