柚子快報激活碼778899分享:數(shù)據(jù)庫 MongoDB聚合操作
柚子快報激活碼778899分享:數(shù)據(jù)庫 MongoDB聚合操作
文章目錄
聚合操作單一作用聚合聚合管道什么是 MongoDB 聚合框架管道(Pipeline)和階段(Stage)常用的管道聚合階段聚合表達式數(shù)據(jù)準備$project$match$count$group
accumulator操作符$unwind$limit$skip$sort$lookup案例聚合操作案例1聚合操作案例2
MapReduce
聚合操作
聚合操作處理數(shù)據(jù)記錄并返回計算結(jié)果。聚合操作組值來自多個文檔,可以對分組數(shù)據(jù)執(zhí)行各種操作以返回單個結(jié)果。聚合操作包含三類:單一作用聚合、聚合管道、MapReduce。
單一作用聚合:提供了對常見聚合過程的簡單訪問,操作都從單個集合聚合文檔。聚合管道是一個數(shù)據(jù)聚合的框架,模型基于數(shù)據(jù)處理流水線的概念。文檔進入多級管道,將 文檔轉(zhuǎn)換為聚合結(jié)果。MapReduce操作具有兩個階段:處理每個文檔并向每個輸入文檔發(fā)射一個或多個對象的map階段,以及reduce組合map操作的輸出階段。
單一作用聚合
MongoDB提供 db.collection.estimatedDocumentCount(), db.collection.count(), db.collection.distinct() 這類單一作用的聚合函數(shù)。 所有這些操作都聚合來自單個集合的文檔。雖然這些操作提供了對公共聚合過程的簡單訪問,但它們?nèi)狈酆瞎艿篮蚼ap-Reduce的靈活性和功能。
db.collection.estimatedDocumentCount()返回集合或視圖中所有文檔的計數(shù)db.collection.count()返回與find()集合或視圖的查詢匹配的文檔計數(shù) 。等同于 db.collection.find(query).count()構(gòu)造db.collection.distinct()在單個集合或視圖中查找指定字段的不同值,并在數(shù)組中返回結(jié)果。
#檢索books集合中所有文檔的計數(shù)
db.books.estimatedDocumentCount()
#計算與查詢匹配的所有文檔
db.books.count({favCount:{$gt:50}})
#返回不同type的數(shù)組
db.books.distinct("type")
#返回收藏數(shù)大于90的文檔不同type的數(shù)組
db.books.distinct("type",{favCount:{$gt:90}})
注意:在分片群集上,如果存在孤立文檔或正在進行塊遷移,則db.collection.count()沒有查詢謂詞可能導致計數(shù)不準確。要避免這些情況,請在分片群集上使用 db.collection.aggregate()方法。
聚合管道
什么是 MongoDB 聚合框架
MongoDB 聚合框架(Aggregation Framework)是一個計算框架,它可以:
作用在一個或幾個集合上;對集合中的數(shù)據(jù)進行的一系列運算;將這些數(shù)據(jù)轉(zhuǎn)化為期望的形式;
從效果而言,聚合框架相當于 SQL 查詢中的GROUP BY、 LEFT OUTER JOIN 、 AS等。
管道(Pipeline)和階段(Stage)
整個聚合運算過程稱為管道(Pipeline),它是由多個階段(Stage)組成的, 每個管道:
接受一系列文檔(原始數(shù)據(jù));每個階段對這些文檔進行一系列運算;結(jié)果文檔輸出給下一個階段;
聚合管道操作語法
pipeline = [$stage1, $stage2, ...$stageN];
db.collection.aggregate(pipeline, {options})
pipelines 一組數(shù)據(jù)聚合階段。除
o
u
t
、
out、
out、Merge和$geonear階段之外,每個階段都可以在管道中出現(xiàn)多次。options 可選,聚合操作的其他參數(shù)。包含:查詢計劃、是否使用臨時文件、 游標、最大操作時間、讀寫策略、強制索引等等
常用的管道聚合階段
聚合管道包含非常豐富的聚合階段,下面是最常用的聚合階段
階段描述SQL等價運算符$match篩選條件WHERE$project投影AS$lookup左外連接LEFT OUTER JOIN$sort排序ORDER BY$group分組GROUP BY
s
k
i
p
/
skip/
skip/limit分頁$unwind展開數(shù)組$graphLookup圖搜索
f
a
c
e
t
/
facet/
facet/bucket分面搜索
文檔:Aggregation Pipeline Stages — MongoDB Manual
聚合表達式
獲取字段信息
$
$
常量表達式
$literal :
系統(tǒng)變量表達式
$$
$$CURRENT 指示管道中當前操作的文檔
數(shù)據(jù)準備
準備數(shù)據(jù)集,執(zhí)行腳本
var tags = ["nosql","mongodb","document","developer","popular"];
var types = ["technology","sociality","travel","novel","literature"];
var books=[];
for(var i=0;i<50;i++){
var typeIdx = Math.floor(Math.random()*types.length);
var tagIdx = Math.floor(Math.random()*tags.length);
var tagIdx2 = Math.floor(Math.random()*tags.length);
var favCount = Math.floor(Math.random()*100);
var username = "xx00"+Math.floor(Math.random()*10);
var age = 20 + Math.floor(Math.random()*15);
var book = {
title: "book-"+i,
type: types[typeIdx],
tag: [tags[tagIdx],tags[tagIdx2]],
favCount: favCount,
author: {name:username,age:age}
};
books.push(book)
}
db.books.insertMany(books);
$project
投影操作, 將原始字段投影成指定名稱, 如將集合中的 title 投影成 name
db.books.aggregate([{$project:{name:"$title"}}])
$project 可以靈活控制輸出文檔的格式,也可以剔除不需要的字段
db.books.aggregate([{$project:{name:"$title",_id:0,type:1,author:1}}])
從嵌套文檔中排除字段
db.books.aggregate([
{$project:{name:"$title",_id:0,type:1,"author.name":1}}
])
或者
db.books.aggregate([
{$project:{name:"$title",_id:0,type:1,author:{name:1}}}
])
$match
m
a
t
c
h
用于對文檔進行篩選,之后可以在得到的文檔子集上做聚合,
match用于對文檔進行篩選,之后可以在得到的文檔子集上做聚合,
match用于對文檔進行篩選,之后可以在得到的文檔子集上做聚合,match可以使用除了地理空間之外的所有常規(guī)查詢操作符,在實際應用中盡可能將
m
a
t
c
h
放在管道的前面位置。這樣有兩個好處:一是可以快速將不需要的文檔過濾掉,以減少管道的工作量;二是如果再投射和分組之前執(zhí)行
match放在管道的前面位置。這樣有兩個好處:一是可以快速將不需要的文檔過濾掉,以減少管道的工作量;二是如果再投射和分組之前執(zhí)行
match放在管道的前面位置。這樣有兩個好處:一是可以快速將不需要的文檔過濾掉,以減少管道的工作量;二是如果再投射和分組之前執(zhí)行match,查詢可以使用索引。
db.books.aggregate([{$match:{type:"technology"}}])
篩選管道操作和其他管道操作配合時候時,盡量放到開始階段,這樣可以減少后續(xù)管道操作符要操作的文檔數(shù),提升效率
db.books.aggregate([
{$match:{type:"technology"}},
{$project:{name:"$title",_id:0,type:1,author:{name:1}}}
])
$count
計數(shù)并返回與查詢匹配的結(jié)果數(shù)
db.books.aggregate([
{$match:{type:"technology"}},
{$count: "type_count"}
])
$match階段篩選出type匹配technology的文檔,并傳到下一階段; $count階段返回聚合管道中剩余文檔的計數(shù),并將該值分配給type_count
$group
按指定的表達式對文檔進行分組,并將每個不同分組的文檔輸出到下一個階段。輸出文檔包含一個_id字段,該字段按鍵包含不同的組。輸出文檔還可以包含計算字段,該字段保存由$group的_id字段分組的一些accumulator表達式的值。 $group不會輸出具體的文檔而只是統(tǒng)計信息。
{ $group: { _id:
_id字段是必填的;但是,可以指定_id值為null來為整個輸入文檔計算累計值。剩余的計算字段是可選的,并使用運算符進行計算。_id和表達式可以接受任何有效的表達式。
accumulator操作符
名稱描述類比sql$avg計算均值avg$first返回每組第一個文檔,如果有排序,按照排序,如果沒有按照默認的存儲的順序的第一個文檔。limit 0,1$last返回每組最后一個文檔,如果有排序,按照排序,如果沒有按照默認的存儲的順序的最后個文檔。-$max根據(jù)分組,獲取集合中所有文檔對應值得最大值。max$min根據(jù)分組,獲取集合中所有文檔對應值得最小值。min$push將指定的表達式的值添加到一個數(shù)組中。-$addToSet將表達式的值添加到一個集合中(無重復值,無序)。-$sum計算總和sum$stdDevPop返回輸入值的總體標準偏差(population standard deviation)-$stdDevSamp返回輸入值的樣本標準偏差(the sample standard deviation)-
g
r
o
u
p
階段的內(nèi)存限制為
100
M
。默認情況下,如果
s
t
a
g
e
超過此限制,
group階段的內(nèi)存限制為100M。默認情況下,如果stage超過此限制,
group階段的內(nèi)存限制為100M。默認情況下,如果stage超過此限制,group將產(chǎn)生錯誤。但是,要允許處理大型數(shù)據(jù)集,請將allowDiskUse選項設(shè)置為true以啟用$group操作以寫入臨時文件。book的數(shù)量,收藏總數(shù)和平均值
db.books.aggregate([
{$group:{_id:null,count:{$sum:1},pop:{$sum:"$favCount"},avg:{$avg:"$favCount"}}}
])
統(tǒng)計每個作者的book收藏總數(shù)
db.books.aggregate([
{$group:{_id:"$author.name",pop:{$sum:"$favCount"}}}
])
統(tǒng)計每個作者的每本book的收藏數(shù)
db.books.aggregate([
{$group:{_id:{name:"$author.name",title:"$title"},pop:{$sum:"$favCount"}}}
])
每個作者的book的type合集
db.books.aggregate([
{$group:{_id:"$author.name",types:{$addToSet:"$type"}}}
])
$unwind
可以將數(shù)組拆分為單獨的文檔v3.2+支持如下語法:
{
$unwind:
{
#要指定字段路徑,在字段名稱前加上$符并用引號括起來。
path:
#可選,一個新字段的名稱用于存放元素的數(shù)組索引。該名稱不能以$開頭。
includeArrayIndex:
#可選,default :false,若為true,如果路徑為空,缺少或為空數(shù)組,則$unwind輸出文檔
preserveNullAndEmptyArrays:
} }
姓名為xx006的作者的book的tag數(shù)組拆分為多個文檔
db.books.aggregate([
{$match:{"author.name":"xx006"}},
{$unwind:"$tag"}
])
db.books.aggregate([
{$match:{"author.name":"xx006"}}
])
每個作者的book的tag合集
db.books.aggregate([
{$unwind:"$tag"},
{$group:{_id:"$author.name",types:{$addToSet:"$tag"}}}
])
案例示例數(shù)據(jù)
db.books.insert([
{
"title" : "book-51",
"type" : "technology",
"favCount" : 11,
"tag":[],
"author" : {
"name" : "fox",
"age" : 28
}
},{
"title" : "book-52",
"type" : "technology",
"favCount" : 15,
"author" : {
"name" : "fox",
"age" : 28
}
},{
"title" : "book-53",
"type" : "technology",
"tag" : [
"nosql",
"document"
],
"favCount" : 20,
"author" : {
"name" : "fox",
"age" : 28
}
}])
測試
# 使用includeArrayIndex選項來輸出數(shù)組元素的數(shù)組索引
db.books.aggregate([
{$match:{"author.name":"fox"}},
{$unwind:{path:"$tag", includeArrayIndex: "arrayIndex"}}
])
# 使用preserveNullAndEmptyArrays選項在輸出中包含缺少size字段,null或空數(shù)組的文檔
db.books.aggregate([
{$match:{"author.name":"fox"}},
{$unwind:{path:"$tag", preserveNullAndEmptyArrays: true}}
])
$limit
限制傳遞到管道中下一階段的文檔數(shù)
db.books.aggregate([
{$limit : 5 }
])
此操作僅返回管道傳遞給它的前5個文檔。
l
i
m
i
t
對其傳遞的文檔內(nèi)容沒有影響。
<
b
r
/
>
注意:當
limit對其傳遞的文檔內(nèi)容沒有影響。
注意:當
limit對其傳遞的文檔內(nèi)容沒有影響。
注意:當sort在管道中的
l
i
m
i
t
之前立即出現(xiàn)時,
limit之前立即出現(xiàn)時,
limit之前立即出現(xiàn)時,sort操作只會在過程中維持前n個結(jié)果,其中n是指定的限制,而MongoDB只需要將n個項存儲在內(nèi)存中。
$skip
跳過進入stage的指定數(shù)量的文檔,并將其余文檔傳遞到管道中的下一個階段
db.books.aggregate([
{$skip : 5 }
])
此操作將跳過管道傳遞給它的前5個文檔。 $skip對沿著管道傳遞的文檔的內(nèi)容沒有影響。
$sort
對所有輸入文檔進行排序,并按排序順序?qū)⑺鼈兎祷氐焦艿?。語法:
{ $sort: {
要對字段進行排序,請將排序順序設(shè)置為1或-1,以分別指定升序或降序排序,如下例所示:
db.books.aggregate([
{$sort : {favCount:-1,title:1}}
])
$lookup
Mongodb 3.2版本新增,主要用來實現(xiàn)多表關(guān)聯(lián)查詢, 相當關(guān)系型數(shù)據(jù)庫中多表關(guān)聯(lián)查詢。每個輸入待處理的文檔,經(jīng)過$lookup 階段的處理,輸出的新文檔中會包含一個新生成的數(shù)組(可根據(jù)需要命名新key )。數(shù)組列存放的數(shù)據(jù)是來自被Join集合的適配文檔,如果沒有,集合為空(即 為[ ])語法:
db.collection.aggregate([{
$lookup: {
from: "
localField: "
foreignField: "
as: "
}
})
from同一個數(shù)據(jù)庫下等待被Join的集合。localField源集合中的match值,如果輸入的集合中,某文檔沒有 localField這個Key(Field),在處理的過程中,會默認為此文檔含有 localField:null的鍵值對。foreignField待Join的集合的match值,如果待Join的集合中,文檔沒有foreignField值,在處理的過程中,會默認為此文檔含有 foreignField:null的鍵值對。as為輸出文檔的新增值命名。如果輸入的集合中已存在該值,則會覆蓋掉
注意:null = null 此為真其語法功能類似于下面的偽SQL語句:
SELECT *,
FROM collection
WHERE
FROM
WHERE
案例
數(shù)據(jù)準備
db.customer.insert({customerCode:1,name:"customer1",phone:"13112345678",address:"test1"})
db.customer.insert({customerCode:2,name:"customer2",phone:"13112345679",address:"test2"})
db.order.insert({orderId:1,orderCode:"order001",customerCode:1,price:200})
db.order.insert({orderId:2,orderCode:"order002",customerCode:2,price:400})
db.orderItem.insert({itemId:1,productName:"apples",qutity:2,orderId:1})
db.orderItem.insert({itemId:2,productName:"oranges",qutity:2,orderId:1})
db.orderItem.insert({itemId:3,productName:"mangoes",qutity:2,orderId:1})
db.orderItem.insert({itemId:4,productName:"apples",qutity:2,orderId:2})
db.orderItem.insert({itemId:5,productName:"oranges",qutity:2,orderId:2})
db.orderItem.insert({itemId:6,productName:"mangoes",qutity:2,orderId:2})
關(guān)聯(lián)查詢
db.customer.aggregate([
{$lookup: {
from: "order",
localField: "customerCode",
foreignField: "customerCode",
as: "customerOrder"
}
}
])
db.order.aggregate([
{$lookup: {
from: "customer",
localField: "customerCode",
foreignField: "customerCode",
as: "curstomer"
}
},
{$lookup: {
from: "orderItem",
localField: "orderId",
foreignField: "orderId",
as: "orderItem"
}
}
])
聚合操作案例1
統(tǒng)計每個分類的book文檔數(shù)量
db.books.aggregate([
{$group:{_id:"$type",total:{$sum:1}}},
{$sort:{total:-1}}
])
標簽的熱度排行,標簽的熱度則按其關(guān)聯(lián)book文檔的收藏數(shù)(favCount)來計算
db.books.aggregate([
{$match:{favCount:{$gt:0}}},
{$unwind:"$tag"},
{$group:{_id:"$tag",total:{$sum:"$favCount"}}},
{$sort:{total:-1}}
])
$match階段:用于過濾favCount=0的文檔。$unwind階段:用于將標簽數(shù)組進行展開,這樣一個包含3個標簽的文檔會被拆解為3個條目。
g
r
o
u
p
階段:對拆解后的文檔進行分組計算,
group階段:對拆解后的文檔進行分組計算,
group階段:對拆解后的文檔進行分組計算,sum:"$favCount"表示按favCount字段進行累加。$sort階段:接收分組計算的輸出,按total得分進行排序。
統(tǒng)計book文檔收藏數(shù)[0,10),[10,60),[60,80),[80,100),[100,+∞)
db.books.aggregate([{
$bucket:{
groupBy:"$favCount",
boundaries:[0,10,60,80,100],
default:"other",
output:{"count":{$sum:1}}
}
}])
聚合操作案例2
導入郵政編碼數(shù)據(jù)集:https://media.mongodb.org/zips.json使用mongoimport工具導入數(shù)據(jù)
mongoimport -h 192.168.65.174 -d test -u fox -p fox --authenticationDatabase=admin -c zips --file D:\ProgramData\mongodb\import\zips.json
h,–host :代表遠程連接的數(shù)據(jù)庫地址,默認連接本地Mongo數(shù)據(jù)庫; –port:代表遠程連接的數(shù)據(jù)庫的端口,默認連接的遠程端口27017; -u,–username:代表連接遠程數(shù)據(jù)庫的賬號,如果設(shè)置數(shù)據(jù)庫的認證,需要指定用戶賬號; -p,–password:代表連接數(shù)據(jù)庫的賬號對應的密碼; -d,–db:代表連接的數(shù)據(jù)庫; -c,–collection:代表連接數(shù)據(jù)庫中的集合; -f, --fields:代表導入集合中的字段; –type:代表導入的文件類型,包括csv和json,tsv文件,默認json格式; –file:導入的文件名稱 –headerline:導入csv文件時,指明第一行是列名,不需要導入;
返回人口超過1000萬的州
db.zips.aggregate( [
{ $group: { _id: "$state", totalPop: { $sum: "$pop" } } },
{ $match: { totalPop: { $gte: 10*1000*1000 } } }
] )
這個聚合操作的等價SQL是: SELECT state, SUM(pop) AS totalPop FROM zips GROUP BY state HAVING totalPop >= (1010001000) 返回各州平均城市人口
SELECT state, SUM(pop) AS totalPop
FROM zips
GROUP BY state
HAVING totalPop >= (10*1000*1000)
按州返回最大和最小的城市
db.zips.aggregate( [
{ $group:
{
_id: { state: "$state", city: "$city" },
pop: { $sum: "$pop" }
}
},
{ $sort: { pop: 1 } },
{ $group:
{
_id : "$_id.state",
biggestCity: { $last: "$_id.city" },
biggestPop: { $last: "$pop" },
smallestCity: { $first: "$_id.city" },
smallestPop: { $first: "$pop" }
}
},
{ $project:
{ _id: 0,
state: "$_id",
biggestCity: { name: "$biggestCity", pop: "$biggestPop" },
smallestCity: { name: "$smallestCity", pop: "$smallestPop" }
}
}
] )
MapReduce
MapReduce操作將大量的數(shù)據(jù)處理工作拆分成多個線程并行處理,然后將結(jié)果合并在一起。MongoDB提供的Map-Reduce非常靈活,對于大規(guī)模數(shù)據(jù)分析也相當實用。MapReduce具有兩個階段:
將具有相同Key的文檔數(shù)據(jù)整合在一起的map階段組合map操作的結(jié)果進行統(tǒng)計輸出的reduce階段
MapReduce的基本語法
db.collection.mapReduce(
function() {emit(key,value);}, //map 函數(shù)
function(key,values) {return reduceFunction}, //reduce 函數(shù)
{
out:
query:
sort:
limit:
finalize:
scope:
jsMode:
verbose:
bypassDocumentValidation:
}
)
map,將數(shù)據(jù)拆分成鍵值對,交給reduce函數(shù)reduce,根據(jù)鍵將值做統(tǒng)計運算out,可選,將結(jié)果匯入指定表quey,可選篩選數(shù)據(jù)的條件,篩選的數(shù)據(jù)送入mapsort,排序完后,送入maplimit,限制送入map的文檔數(shù)finalize,可選,修改reduce的結(jié)果后進行輸出scope,可選,指定map、reduce、finalize的全局變量jsMode,可選,默認false。在mapreduce過程中是否將數(shù) 據(jù)轉(zhuǎn)換成bson格式。verbose,可選,是否在結(jié)果中顯示時間,默認falsebypassDocmentValidation,可選,是否略過數(shù)據(jù)校驗
統(tǒng)計type為travel的不同作者的book文檔收藏數(shù)
db.books.mapReduce(
function(){emit(this.type,this.favCount)},
function(key,values){return Array.sum(values)},
{
query:{type:"travel"},
out: "books_favCount"
}
)
從MongoDB 5.0開始,map-reduce操作已被棄用。聚合管道比映射-reduce操作提供更好的性能和可用性。Map-reduce操作可以使用聚合管道操作符重寫,例如
g
r
o
u
p
、
group、
group、merge等。dn
柚子快報激活碼778899分享:數(shù)據(jù)庫 MongoDB聚合操作
推薦鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。