概述html
數據存儲是爲了可查詢,統計。若數據只需存儲,不須要查詢,這種數據也沒有多大價值git
本篇介紹Mongodbgithub
準備工做mongodb
準備10000條數據express
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的聚合函數操做都在db.collection.aggregate,經過定義聚合管道(一組規則),達到分組,統計等功能,下面介紹經常使用的幾種聚合函數app
分組管道($group)less
格式dom
{ $group: { _id: <expression>, // Group By Expression <field1>: { <accumulator1> : <expression1> }, ... } }
_id 是分組字段,若指定_id = null 或常量字段,就是將整個結果集分組。ide
分組統計字段格式{ <accumulator1> : <expression1> }
累計器操做(Accumulator Operator)參考Accumulator Operator
假設如今須要統計天天每一個小時的訂單總價格,平均價格,最大,最小,總訂單數等
db.order.aggregate([ { $group: { //分組字段,這裏用到$dateToString格式化,這裏按小時統計 _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" }, //總訂單數 totalOrders: { $sum: 1 }, } } ])
返回結果
{ "_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> } }
這個比較簡單,就是篩選數據
假設我如今須要篩選金額在(10,15)之間的
db.orders.aggregate([ { $match: { "price": { $gt: 10, $lt: 15 } } } ])
排序管道($sort)
格式
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
指定字段排序,1:升序,-1:倒序
限制條數($limit)
格式
{ $limit: <positive integer> }
Mongodb的聚合管道有不少,具體不一一列出,參考Aggregation Pipeline Stages — MongoDB Manual
帶有(aggregation)就是均可以用於聚合管道
說了那麼多,其實都沒有使用Mongodb聚合函數最強大的功能,就是組合管道使用,查詢咱們須要數據,由於Mongodb提供的聚合管道函數很是多,因此組合起來使用是很是強大。
值得注意是管道的順序,Mongodb是按你定義的順序,將每一步執行的結果集傳給下一個管道處理,輸出是最後一個管道的結果集,因此不一樣的管道順序會有可能獲得不是預期的結果,甚至報錯(這種狀況報錯甚至比獲得不是預期的結果可能還好)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 } } ])
解決思路
固定集合
概述
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.
從上面定義能夠看出固定集合具備幾個特性
根據固定集合特性,固定集合適合用於如下場景
固定集合限制
固定集合使用
1. 建立固定集合
db.createCollection("log", { capped : true, size : 4096, max : 5000 } )
字段 | 必須 | 說明 |
---|---|---|
capped | 是 | 是否建立固定集合 |
size | 是 | 固定集合大小,單位:字節 |
max | 否 | 文檔數量大小限制 |
size 和 max 是或關係,超出其中一個限制都會覆蓋舊文檔
2. 檢查集合是否固定集合
db.collection.isCapped()
3. 將一個非固定的集合轉換固定集合
db.runCommand({"convertToCapped": "mycoll", size: 100000});
測試固定集合
1. 超過限制文檔數
// 1. 建立固定集合,大小1M,最大文檔數量10 db.createCollection("log", { capped: true, size: 1024 * 1024, max: 10 }); // 2. 插入200條數據 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(), }); }
再查詢如今Mongodb存儲狀況
db.log.stats()
能夠看出每一個對象都是佔有78個字節,由於字段都是定長的
2. 驗證操做存儲大小
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的字段設置小於4096,Mongodb將會提供一個256的倍數的數據存儲大小
假設256的大小,256 / 78 = 3.282051282051282,應該能存3個文檔
// 1. 刪除以前固定集合 db.log.drop(); // 2. 建立固定集合,size < 78 , 驗證是否建立一個256的大小 db.createCollection("log", { capped: true, size: 78 }); // 2. 插入200條數據 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(), }); }
查看集合統計
db.log.stats()
能夠看出log集合使用了234個字節(78 * 3),也即3個文檔的大小,最大能使用大小是256
3. 查詢固定集合
Mongodb若沒指定排序字段,是按存入順序檢索,能夠使用.sort( { $natural: -1 } )改變輸出順序
db.log.find({}).sort( { $natural: -1 } )
4. 將非固定集合轉換固定集合
將order轉換試試
db.runCommand({"convertToCapped": "order", size: 8096});
查看order集合統計
只剩下90條數據
轉發請標明出處:https://www.cnblogs.com/WilsonPan/p/12692642.html