摘要:總之,通過(guò)這樣的保存方式,我們能夠?qū)崿F(xiàn)當(dāng)學(xué)生成績(jī)改變時(shí),快速簡(jiǎn)單的修改數(shù)據(jù)庫(kù)記錄,而又能夠?qū)崟r(shí)的查詢出新的排名了。
當(dāng)我們將考試分?jǐn)?shù)錄入系統(tǒng)時(shí),會(huì)要對(duì)學(xué)生的分?jǐn)?shù)進(jìn)行一個(gè)排名,這個(gè)不困難。困難的是當(dāng)學(xué)生的分?jǐn)?shù)變更時(shí),如何實(shí)時(shí)更新這些排名?
如果我們將排名保存為一個(gè)字段,那么意味著每次修改分?jǐn)?shù)都會(huì)導(dǎo)致重新計(jì)算排名,以及更新數(shù)據(jù)庫(kù)中的排名字段值。這個(gè)計(jì)算量可大可小,極端的情況下,如果一個(gè)學(xué)生的分?jǐn)?shù)從第一名變成 0(比如因?yàn)樽鞅锥煽?jī)清零),那么所有學(xué)生的排名都有可能要改,這就導(dǎo)致大批量的數(shù)據(jù)庫(kù) update 操作。
這種方式顯然是效率非常低的。那么這里給出一個(gè)解決辦法,能夠?qū)崿F(xiàn)修改分?jǐn)?shù)的同時(shí),排名立刻得到更新,而無(wú)需大規(guī)模修改數(shù)據(jù)庫(kù)記錄。本文以 MongoDB 為例介紹如何保存這些分?jǐn)?shù)。
假設(shè)我們有 10 個(gè)學(xué)生的考試成績(jī)分別為:
50 50 50 60 60 60 60 80 90 100
那么我可以創(chuàng)建一條排名記錄(假設(shè)這條記錄在集合 scores 里面),內(nèi)容如下:
{ key: "exam_001", scoreMap: [ {score:50, count:3}, {score:60, count:4}, {score:80, count:1}, {score:90, count:1}, {score:100, count:1} ] }
看到這里你就應(yīng)該明白了,我保存的只是每個(gè)分?jǐn)?shù)對(duì)應(yīng)的人數(shù)。這樣當(dāng)我需要添加一個(gè) 80 分的成績(jī)時(shí),我只需將 {score:80, count:1} 改為 {score:80, count:2} 即可。
這種情況下如何獲得一個(gè)學(xué)生的排名呢?首先要說(shuō)明,每個(gè)學(xué)生對(duì)應(yīng)的分?jǐn)?shù)并沒(méi)有保存在這里(你可以保存到另外的表里面,然后查出該學(xué)生的分?jǐn)?shù)),這里保存的是分?jǐn)?shù)的排名,而不是學(xué)生的排名。所以你查出分?jǐn)?shù)后,對(duì) scoreMap 數(shù)組中所有 score 大于該分?jǐn)?shù)的元素的 count 值進(jìn)行一個(gè)總和即可。
比如我想知道 85 分是第幾名,從數(shù)組中可以算知大于 85 分的人數(shù)為 2,那么 85 分自然是第 3 名了。
那么在 MongoDB 里面,可以這樣查詢:
db.scores.aggregate([ {$match:{key:"exam_001"}}, {$unwind:"$scoreMap"}, {$match:{"scoreMap.score": {$gt: 85}}}, {$group:{_id:0,count:{$sum:"$scoreMap.count"}}} ]);
查出來(lái)的結(jié)果為:
{ "_id" : 0, "count" : 2 }
這種保存方式有一個(gè)極大的好處,就是不論有多少學(xué)生參加排名,我的記錄數(shù)始終是有限的。假設(shè)這門(mén)考試總分 100 分,有 100 萬(wàn)學(xué)生參加排名,那么極端情況下 scoreMap 數(shù)組中也只會(huì)有 201 個(gè)元素(0, 0.5, 1, ... 99.5, 100)。也就是說(shuō),它的值空間是非常有限的。
有人會(huì)進(jìn)一步提出:如果我將班級(jí)平均分(帶兩位小數(shù))也加入這樣的排名呢?值空間將會(huì)變成幾萬(wàn)個(gè),這樣的排名查詢起來(lái)豈不會(huì)很慢?
實(shí)際上不是這樣子的。雖然兩位小數(shù)使得值空間很大,但參與排名的班級(jí)非常有限,也就是說(shuō)值的實(shí)際數(shù)量很小。如果是 100 個(gè)班級(jí)參與排名,不存在相同平均分的情況下, scoreMap 數(shù)組中也只有 100 個(gè)元素。所以計(jì)算排名絲毫不會(huì)慢下來(lái)。
如何更新現(xiàn)在我們的排名已經(jīng)不再是直接保存在數(shù)據(jù)庫(kù),而是在查詢的時(shí)候算出來(lái),那么當(dāng)一個(gè)學(xué)生的成績(jī)變更時(shí),我應(yīng)該如何更新數(shù)據(jù)庫(kù)記錄呢?
當(dāng)一個(gè)學(xué)生的成績(jī)從 a 變?yōu)?b 時(shí),我們需要做兩個(gè)操作:
將成績(jī)?yōu)?a 的學(xué)生數(shù)量 -1;
將成績(jī)?yōu)?b 的學(xué)生數(shù)量 +1。
在 MongoDB 中,更新 scoreMap 數(shù)組元素的語(yǔ)句是這樣的:
給某個(gè)分?jǐn)?shù)的人數(shù)加一的時(shí)候:
db.scores.update( {key:"exam_001", scoreMap:{$elemMatch:{score:99.5}}}, {$inc:{"scoreMap.$.count":1}} )
給某個(gè)分?jǐn)?shù)的人數(shù)減一的時(shí)候:
db.scores.update( {key:"exam_001", scoreMap:{$elemMatch:{score:99.5,count:{$gt:0}}}}, {$inc:{"scoreMap.$.count":-1}} )
注意減一的時(shí)候,查詢條件加上了一個(gè) count:{$gt:0} 的判斷,這是為了避免人數(shù)變成負(fù)數(shù)。
總之,通過(guò)這樣的保存方式,我們能夠?qū)崿F(xiàn)當(dāng)學(xué)生成績(jī)改變時(shí),快速簡(jiǎn)單的修改數(shù)據(jù)庫(kù)記錄,而又能夠?qū)崟r(shí)的查詢出新的排名了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/18816.html
摘要:中文資料導(dǎo)航官網(wǎng)七牛鏡像深入淺出系列進(jìn)階必讀中文文檔被誤解的編寫(xiě)實(shí)戰(zhàn)系列熱門(mén)模塊排行榜,方便找出你想要的模塊多線程,真正的非阻塞淺析的類(lèi)利用編寫(xiě)異步多線程的實(shí)例中與的區(qū)別管道拒絕服務(wù)漏洞高級(jí)編程業(yè)界新聞看如何評(píng)價(jià)他們的首次嘗鮮程序員如何說(shuō)服 node.js中文資料導(dǎo)航 Node.js HomePage Node官網(wǎng)七牛鏡像 Infoq深入淺出Node.js系列(進(jìn)階必讀) Nod...
摘要:介紹在博客爬蟲(chóng)爬取中國(guó)高校排名前名并寫(xiě)入中,我們利用來(lái)寫(xiě)爬蟲(chóng),將中的大學(xué)排名表格爬取出來(lái),并存入到中。本次分享將用的來(lái)實(shí)現(xiàn)相同的功能,并將爬取到的數(shù)據(jù)存入到數(shù)據(jù)庫(kù)中。 介紹 ??在博客:Python爬蟲(chóng)——爬取中國(guó)高校排名前100名并寫(xiě)入MySQL中,我們利用Python來(lái)寫(xiě)爬蟲(chóng),將http://gaokao.xdf.cn/201702/1... 中的大學(xué)排名表格爬取出來(lái),并存入到My...
摘要:介紹在博客爬蟲(chóng)爬取中國(guó)高校排名前名并寫(xiě)入中,我們利用來(lái)寫(xiě)爬蟲(chóng),將中的大學(xué)排名表格爬取出來(lái),并存入到中。本次分享將用的來(lái)實(shí)現(xiàn)相同的功能,并將爬取到的數(shù)據(jù)存入到數(shù)據(jù)庫(kù)中。 介紹 ??在博客:Python爬蟲(chóng)——爬取中國(guó)高校排名前100名并寫(xiě)入MySQL中,我們利用Python來(lái)寫(xiě)爬蟲(chóng),將http://gaokao.xdf.cn/201702/1... 中的大學(xué)排名表格爬取出來(lái),并存入到My...
閱讀 2847·2021-11-19 11:30
閱讀 3114·2021-11-15 11:39
閱讀 1886·2021-08-03 14:03
閱讀 2062·2019-08-30 14:18
閱讀 2112·2019-08-30 11:16
閱讀 2270·2019-08-29 17:23
閱讀 2663·2019-08-28 18:06
閱讀 2599·2019-08-26 12:22