【Mongodb】聚合查詢 && 固定集合

概述


數(shù)據(jù)存儲是為了可查詢组底,統(tǒng)計丈积。若數(shù)據(jù)只需存儲筐骇,不需要查詢,這種數(shù)據(jù)也沒有多大價值

本篇介紹Mongodb

  • 聚合查詢(Aggregation)
  • 固定集合(Capped Collections)

準(zhǔn)備工作


準(zhǔn)備10000條數(shù)據(jù)

var orders = new Array();
for (var i = 10000; i < 20000; i++) {
    orders[i] = {
        orderNo: i + Math.random().toString().substr(3, 3),
        price: Math.round(Math.random() * 10000) / 100,
        qty: Math.floor(Math.random() * 10) + 1,
        orderTime: new Date(new Date().setSeconds(Math.floor(Math.random() * 10000)))
    };
}
db.order.insert(orders);

聚合查詢


Mongodb的聚合函數(shù)操作都在db.collection.aggregate江滨,通過定義聚合管道(一組規(guī)則)铛纬,達(dá)到分組,統(tǒng)計等功能唬滑,下面介紹常用的幾種聚合函數(shù)

  • 分組管道($group)
    格式
{
  $group:
    {
      _id: <expression>, // Group By Expression
      <field1>: { <accumulator1> : <expression1> },
      ...
    }
 }

_id 是分組字段告唆,若指定_id = null 或常量字段,就是將整個結(jié)果集分組间雀。
分組統(tǒng)計字段格式{ <accumulator1> : <expression1> }

累計器操作(Accumulator Operator)參考Accumulator Operator

假設(shè)現(xiàn)在需要統(tǒng)計每天每個小時的訂單總價格,平均價格镊屎,最大惹挟,最小,總訂單數(shù)等

db.order.aggregate([
    {
        $group: {
            //分組字段缝驳,這里用到$dateToString格式化连锯,這里按小時統(tǒng)計
            _id: { $dateToString: { format: "%Y-%m-%d %H", date: "$orderTime" } },
            //總價格
            totalPrice: { $sum: "$price" },
            //分組第一個訂單
            firstOrder: { $first: "$orderNo" },
            //分組最后一個訂單
            lastOrder: { $last: "$orderNo" },
            //平均價格
            averagePrice: { $avg: "$price" },
            //最大價格
            maxPrice: { $max: "$price" },
            //最小價格
            minPrice: { $min: "$price" },
            //總訂單數(shù)
            totalOrders: { $sum: 1 },
        }
    }
])

返回結(jié)果

{ "_id" : "2020-04-12 15", "totalPrice" : 172813.68, "firstOrder" : "10000263", "lastOrder" : "19999275", "averagePrice" : 49.20662870159453, "maxPrice" : 99.94, "minPrice" : 0.01, "totalOrders" : 3512 }
{ "_id" : "2020-04-12 13", "totalPrice" : 80943.98, "firstOrder" : "10004484", "lastOrder" : "19991554", "averagePrice" : 50.780414052697616, "maxPrice" : 99.81, "minPrice" : 0.08, "totalOrders" : 1594 }
{ "_id" : "2020-04-12 14", "totalPrice" : 181710.15, "firstOrder" : "10001745", "lastOrder" : "19998830", "averagePrice" : 49.76996713229252, "maxPrice" : 99.93, "minPrice" : 0.01, "totalOrders" : 3651 }
{ "_id" : "2020-04-12 16", "totalPrice" : 63356.12, "firstOrder" : "10002711", "lastOrder" : "19995793", "averagePrice" : 50.97032984714401, "maxPrice" : 99.95, "minPrice" : 0.01, "totalOrders" : 1243 }
  • 篩選管道($match)
    格式
{ $match: { <query> } }

這個比較簡單,就是篩選數(shù)據(jù)
假設(shè)我現(xiàn)在需要篩選金額在(10用狱,15)之間的

db.orders.aggregate([
    {
        $match: {
            "price": { $gt: 10, $lt: 15 }
        }
    }
])
  • 排序管道($sort)
    格式
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }

指定字段排序运怖,1:升序,-1:倒序

  • 限制條數(shù)($limit)
    格式
{ $limit: <positive integer> }

Mongodb的管道有很多夏伊,具體不一一列出摇展,參考Aggregation Pipeline Stages — MongoDB Manual

image.png

帶有(aggregation)就是都可以用于聚合管道

說了那么多,其實都沒有使用Mongodb聚合函數(shù)最強(qiáng)大的功能溺忧,就是組合管道使用咏连,查詢我們需要數(shù)據(jù),因為Mongodb提供的聚合管道函數(shù)非常多鲁森,所以組合起來使用是非常強(qiáng)大祟滴。
值得注意是管道的順序,Mongodb是按你定義的順序歌溉,將每一步執(zhí)行的結(jié)果集傳給下一個管道處理垄懂,輸出是最后一個管道的結(jié)果集,所以不同的管道順序會有可能得到不是預(yù)期的結(jié)果痛垛,甚至報錯(這種情況報錯甚至比得到不是預(yù)期的結(jié)果可能還好)

假設(shè)現(xiàn)在按每天小時統(tǒng)計符合下列條件的訂單

  • 訂單金額大于10元 小于 50元 && 數(shù)量小于等于5 and
  • 去掉金額最小的50條訂單 && 去掉金額最大的50條訂單 and
  • 統(tǒng)計每個小時內(nèi)訂單數(shù)量草慧,訂單金額
  • 按訂單金額升序輸出
db.order.aggregate([
    {
        $match: { "price": { $gt: 10, $lt: 50 }, "qty": { $lte: 5 } }
    },
    {
        $sort: {
            "price": -1
        }
    },
    {
        $skip: 50
    },
    {
        $sort: {
            "price": 1
        }
    },
    {
        $skip: 50
    },
    {
        $group: {
            _id: { $dateToString: { format: "%Y-%m-%d %H", date: "$orderTime" } },
            totalPrice: { $sum: "$price" },
            totalOrders: { $sum: 1 }

        }
    },
    {
        $sort: {
            "totalPrice": 1
        }
    }
])

解決思路

  1. 篩選符合條件的記錄($match)
  2. 按金額倒序($sort:-1)
  3. 跳過金額最大的50條記錄($skip:50)
  4. 按金額升序($sort:1)
  5. 跳過金額最小的50條記錄($skip:50)
  6. 按每天每小時統(tǒng)計($group)
  7. 統(tǒng)計結(jié)果總金額升序($sort:1)

固定集合


概述

capped-collection are fixed-size collections that support high-throughput operations that insert and retrieve documents based on insertion order. Capped collections work in a way similar to circular buffers: once a collection fills its allocated space, it makes room for new documents by overwriting the oldest documents in the collection.

從上面定義可以看出固定集合具有幾個特性

  • 固定大小
  • 高吞吐量
  • 根據(jù)插入順序檢索文檔
  • 超過限制大小覆蓋舊的文檔

根據(jù)固定集合特性,固定集合適合用于以下場景

  • 只需保留最近的日志查詢系統(tǒng)
  • 緩存數(shù)據(jù)(熱點數(shù)據(jù))
  • 等等

固定集合限制

  • 固定集合的大小創(chuàng)建之后不能修改
  • 不能刪除固定集合里的文檔匙头,只能刪除集合再重新建固定集合
  • 固定集合不能使用固定分區(qū)
  • 聚合管道$out不能使用在固定集合
固定集合使用
  1. 創(chuàng)建固定集合
db.createCollection("log", { capped : true, size : 4096, max : 5000 } )
字段 必須 說明
capped 是?????? 是否創(chuàng)建固定集合
size 固定集合大小冠蒋,單位:字節(jié)
max 文檔數(shù)量大小限制

size 和 max 是或關(guān)系,超出其中一個限制都會覆蓋舊文檔

  1. 檢查集合是否固定集合
db.collection.isCapped()
  1. 將一個非固定的集合轉(zhuǎn)換固定集合
db.runCommand({"convertToCapped": "mycoll", size: 100000});
測試固定集合
  1. 超過限制文檔數(shù)
// 1. 創(chuàng)建固定集合乾胶,大小1M抖剿,最大文檔數(shù)量10
db.createCollection("log", { capped: true, size: 1024 * 1024, max: 10 });

// 2. 插入200條數(shù)據(jù)
for (var i = 0; i < 200; i++) {
    db.log.insertOne({
        "_id": i + 1,
        "userId": Math.floor(Math.random() * 1000),
        "content": "登錄" + ("0000" + i).slice(-4),
        "createTime": new Date(),
    });
}

再查詢現(xiàn)在Mongodb存儲情況

db.log.stats()
image.png

可以看出每個對象都是占有78個字節(jié)朽寞,因為字段都是定長的

  1. 驗證操作存儲大小

If the size field is less than or equal to 4096, then the collection will have a cap of 4096 bytes. Otherwise, MongoDB will raise the provided size to make it an integer multiple of 256.

如果size的字段設(shè)置小于4096,Mongodb將會提供一個256的倍數(shù)的數(shù)據(jù)存儲大小
假設(shè)256的大小斩郎,256 / 78 = 3.282051282051282脑融,應(yīng)該能存3個文檔

// 1. 刪除之前固定集合
db.log.drop();

// 2. 創(chuàng)建固定集合,size < 78 , 驗證是否創(chuàng)建一個256的大小
db.createCollection("log", { capped: true, size: 78 });

// 2. 插入200條數(shù)據(jù)
for (var i = 0; i < 200; i++) {
    db.log.insertOne({
        "_id": i + 1,
        "userId": Math.floor(Math.random() * 1000),
        "content": "登錄" + ("0000" + i).slice(-4),
        "createTime": new Date(),
    });
}

查看集合統(tǒng)計

db.log.stats()

可以看出log集合使用了234個字節(jié)(78 * 3)缩宜,也即3個文檔的大小肘迎,最大能使用大小是256

  1. 查詢固定集合
    Mongodb若沒指定排序字段,是按存入順序檢索锻煌,可以使用.sort( { $natural: -1 } )改變排序
db.log.find({}).sort( { $natural: -1 } )
  1. 將非固定集合轉(zhuǎn)換固定集合

將order轉(zhuǎn)換試試

db.runCommand({"convertToCapped": "order", size: 8096});

查看order集合統(tǒng)計

只剩下90條數(shù)據(jù)

參考文章


Aggregation — MongoDB Manual
Capped Collections — MongoDB Manual

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妓布,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宋梧,更是在濱河造成了極大的恐慌匣沼,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捂龄,死亡現(xiàn)場離奇詭異释涛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)倦沧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門唇撬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人展融,你說我怎么就攤上這事窖认。” “怎么了告希?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵耀态,是天一觀的道長。 經(jīng)常有香客問我暂雹,道長首装,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任杭跪,我火速辦了婚禮仙逻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涧尿。我一直安慰自己系奉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布姑廉。 她就那樣靜靜地躺著缺亮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桥言。 梳的紋絲不亂的頭發(fā)上萌踱,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天葵礼,我揣著相機(jī)與錄音,去河邊找鬼并鸵。 笑死鸳粉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的园担。 我是一名探鬼主播届谈,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼弯汰!你這毒婦竟也來了艰山?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咏闪,失蹤者是張志新(化名)和其女友劉穎曙搬,沒想到半個月后铅匹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡淹接,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年脯倒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甚纲。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哗脖,到底是詐尸還是另有隱情,我是刑警寧澤扳还,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布才避,位于F島的核電站,受9級特大地震影響氨距,放射性物質(zhì)發(fā)生泄漏桑逝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一俏让、第九天 我趴在偏房一處隱蔽的房頂上張望楞遏。 院中可真熱鬧,春花似錦首昔、人聲如沸寡喝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽预鬓。三九已至,卻和暖如春赊颠,著一層夾襖步出監(jiān)牢的瞬間格二,已是汗流浹背劈彪。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留蟋定,地道東北人粉臊。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像驶兜,于是被迫代替她去往敵國和親扼仲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 一抄淑、MongoDB簡介 1.概述 ? MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫屠凶,由C++語言編寫。旨在為WE...
    鄭元吉閱讀 978評論 0 2
  • 簡介 MongoDB 是一個基于分布式文件存儲的NoSQL數(shù)據(jù)庫 由C++語言編寫肆资,運(yùn)行穩(wěn)定矗愧,性能高 旨在為 WE...
    大熊_7d48閱讀 37,305評論 1 9
  • MongoDB 非關(guān)系型數(shù)據(jù)庫 三,關(guān)系數(shù)據(jù)庫的重要概念 1)關(guān)系模型:關(guān)系(二位表)來表達(dá)數(shù)據(jù)及數(shù)據(jù)之間的聯(lián)系 ...
    dushuzhong閱讀 790評論 0 0
  • 什么是Mongodb數(shù)據(jù)庫郑原? MongoDB 是由C++語言編寫的唉韭,是一個基于分布式文件存儲的開源數(shù)據(jù)庫系統(tǒng) Mo...
    瘦不下去了閱讀 669評論 0 0
  • 一、MongoDB簡介 概述MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫犯犁,由C++語言編寫属愤。旨在為WEB應(yīng)用提供...
    王梓懿_1fbc閱讀 495評論 0 3