MongoDB數(shù)據(jù)庫聚合之分組統(tǒng)計$group的用法詳解
前言
MongoDB不像關(guān)系型數(shù)據(jù)庫,普通的查詢不支持匯總,要進行復(fù)雜的分組匯總,需要使用聚合管道,$group
可以說是MongoDB聚合管道進行數(shù)據(jù)分析最常用的一個階段。該階段根據(jù)分組鍵值(組鍵)把文檔分成若干組,每個唯一的鍵值對應(yīng)一個文檔。組鍵通常是一個或多個字段,也可以是表達式的結(jié)果。$group
階段輸出的結(jié)果中,_id
字段的值就是組鍵的值,輸出文檔中還可以包含匯總表達式的字段,匯總表達式的功能非常豐富,下面的列表會簡單介紹,具體的使用方法可以參考詳細說明。
$group的語法
{ $group: { _id: <expression>, // 組鍵,就是分組的鍵值字段或表達式 <field1>: { <accumulator1> : <expression1> }, ... } }
字段說明:
字段 | 說明 |
---|---|
_id | 不可省略,通過_id 表達式指定分組的依據(jù),如果直接指定_id 的值為null 或常量,則把全部的輸入文檔匯總后返回一個文檔 |
field | 可選,匯總表達式計算的結(jié)果 |
_id和field可以是任何合法的表達式。 |
分組匯總操作符
分組匯總操作符比較多,功能豐富且強大,這里簡要介紹其用途,詳細的用法后續(xù)再專文介紹。
操作符 | 用途介紹 |
---|---|
$accumulator | 返回累加結(jié)果 |
$addToSet | 把分組中不重復(fù)的表達式的值作為數(shù)組返回,注意數(shù)組的元素無序的,類似分組內(nèi)的distinct |
$avg | 返回數(shù)值的平均值。非數(shù)值會被忽略 |
$bottom | 按照指定的順序返回分組中最后一個元素 |
$bottomN | 按照指定的順序返回分組中最后N個元素字段的集合,如果分組元素數(shù)量小于N,則返回全部 |
$count | 返回分組內(nèi)的元素數(shù)量 |
$first | 返回分組內(nèi)第一個元素表達式的結(jié)果 |
$firstN | 返回分組內(nèi)前n個元素的聚合。只有文檔有序時才有意義 |
$last | 返回分組中最后一個文檔的表達式的結(jié)果 |
$lastN | 返回分組內(nèi)最后n個元素的聚合。只有文檔有序時才有意義 |
$max | 返回每個分組表達式值的最大值 |
$maxN | 返回分組內(nèi)最大的n個元素的集合 |
$median | 返回分組中的中位數(shù) |
$mergeObjects | 返回分組合并后的文檔 |
$min | 返回分組內(nèi)表達式的最小值 |
$percentile | 返回與指定百分位數(shù)值相對應(yīng)的值的數(shù)組 |
$push | 返回每個分組表達式值的數(shù)組 |
$stdDevPop | 返回標準差 |
$stdDevSamp | 返回樣本標準差 |
$sum | 返回合計值,忽略空值 |
$top | 根據(jù)指定的順序返回組內(nèi)最前面的元素 |
$topN | 根據(jù)指定的順序返回組內(nèi)前N個元素的聚合 |
注意
$group
使用內(nèi)存不能超過100M,超過會報錯。如果想要處理更多數(shù)據(jù)或者少用一些內(nèi)存,可使用allowDiskUse選項把數(shù)據(jù)寫入臨時文件。- 當使用
$first、$last
等操作符時,可以考慮在參與排序的分組字段上添加索引,某些情況下,這些操作可以使用索引快速定位到相應(yīng)的記錄。
一些例子
統(tǒng)計數(shù)量
創(chuàng)建并插入數(shù)據(jù):
db.sales.insertMany([ { "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") }, { "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") }, { "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") }, { "_id" : 4, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") }, { "_id" : 5, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") }, { "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") }, { "_id" : 7, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") }, { "_id" : 8, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") }, ])
統(tǒng)計sales全部文檔數(shù)量
相當于collection.find({}).count()
db.sales.aggregate( [ { $group: { _id: null, count: { $count: { } } } } ] )
結(jié)果:
{ "_id" : null, "count" : 8 }
檢索不同的值,等價于distinct
仍以上例的sales集合數(shù)據(jù)為例
db.sales.aggregate( [ { $group : { _id : "$item" } } ] )
結(jié)果:
{ "_id" : "abc" }
{ "_id" : "jkl" }
{ "_id" : "def" }
{ "_id" : "xyz" }
等價于:
db.sales.distinct("item")
按Item分組
下面的聚合先按照item進行分組,計算每個item銷售總額,并且返回大于等于100的item。
db.sales.aggregate( [ //階段1 { $group : { _id : "$item", totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } } } }, //階段2 { $match: { "totalSaleAmount": { $gte: 100 } } } ] )
階段1:$group
階段,根據(jù)item進行分組,并計算每個item的銷售總額。
階段2:$math
階段,過濾結(jié)果文檔,只返回銷售總額totalSaleAmount
大于等于100的文檔。
結(jié)果:
{ "_id" : "abc", "totalSaleAmount" : Decimal128("170") }
{ "_id" : "xyz", "totalSaleAmount" : Decimal128("150") }
{ "_id" : "def", "totalSaleAmount" : Decimal128("112.5") }
計算總數(shù)、合計和平均值
創(chuàng)建一個sales集合并插入記錄:
db.sales.insertMany([ { "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") }, { "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") }, { "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") }, { "_id" : 4, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") }, { "_id" : 5, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") }, { "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") }, { "_id" : 7, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") }, { "_id" : 8, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") }, ])
按照日期分組
下面的聚合管道計算2014年的銷售總額、平均銷量和銷售數(shù)量
db.sales.aggregate([ //階段1 { $match : { "date": { $gte: new ISODate("2014-01-01"), $lt: new ISODate("2015-01-01") } } }, //階段2 { $group : { _id : { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }, averageQuantity: { $avg: "$quantity" }, count: { $sum: 1 } } }, //階段3 { $sort : { totalSaleAmount: -1 } } ])
階段1使用$math
只允許2014年的數(shù)據(jù)進入下一階段.
階段2使用$group
根據(jù)日期進行分組,統(tǒng)計每個分組的銷售總額、平均銷量和銷售數(shù)量。
階段3使用$sort
按照銷售總額進行降序排序
結(jié)果:
{ "_id" : "2014-04-04", "totalSaleAmount" : Decimal128("200"), "averageQuantity" : 15, "count" : 2 } { "_id" : "2014-03-15", "totalSaleAmount" : Decimal128("50"), "averageQuantity" : 10, "count" : 1 } { "_id" : "2014-03-01", "totalSaleAmount" : Decimal128("40"), "averageQuantity" : 1.5, "count" : 2 }
按控制null分組
下面的聚合操作,指定分組_id為空,計算集合中所有文檔的總銷售額、平均數(shù)量和計數(shù)。
db.sales.aggregate([ { $group : { _id : null, totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }, averageQuantity: { $avg: "$quantity" }, count: { $sum: 1 } } } ])
結(jié)果:
{
"_id" : null,
"totalSaleAmount" : Decimal128("452.5"),
"averageQuantity" : 7.875,
"count" : 8
}
數(shù)據(jù)透視
創(chuàng)建books集合并插入數(shù)據(jù)
db.books.insertMany([ { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 }, { "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 }, { "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }, { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 }, { "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 } ])
根據(jù)作者對標題分組
下面的聚合操作將books集合中的數(shù)據(jù)透視為按作者分組的標題。
db.books.aggregate([ { $group : { _id : "$author", books: { $push: "$title" } } } ])
結(jié)果
{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] }
{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }
根據(jù)作者對文檔分組
db.books.aggregate([ // 階段1 { $group : { _id : "$author", books: { $push: "$$ROOT" } } }, // 階段2 { $addFields: { totalCopies : { $sum: "$books.copies" } } } ])
階段1:分組$group
,根據(jù)作者對文檔進行分組,使用$$ROOT
把文檔作為books的元素。
階段2:$addFields
會在輸出文檔中添加一個字段,即每位作者的圖書總印數(shù)。
結(jié)果:
{
"_id" : "Homer",
"books" :
[
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }
],
"totalCopies" : 20
}{
"_id" : "Dante",
"books" :
[
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }
],
"totalCopies" : 5
}
以上內(nèi)容參考mongodb官方文檔整理而來
總結(jié)
到此這篇關(guān)于MongoDB數(shù)據(jù)庫聚合之分組統(tǒng)計$group的用法詳解的文章就介紹到這了,更多相關(guān)MongoDB分組統(tǒng)計$group用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Windows下MongoDB的下載安裝、環(huán)境配置教程圖解
這篇文章主要介紹了Windows下MongoDB的下載安裝、環(huán)境配置教程詳解,本文給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-06-06MongoDB操作之日期轉(zhuǎn)換方式(string、ISODate、時間戳)
這篇文章主要介紹了MongoDB操作之日期轉(zhuǎn)換方式(string、ISODate、時間戳),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07