MongoDB管道操作符(二)
上篇文章中我們已經學習了MongoDB中幾個基本的管道操作符,本文我們再來看看其他的管道操作符。
本文是MongoDB系列的第十三篇文章,瞭解前面的文章有助於更好的理解本文:
$group
基本操作
$group可以用來對文件進行分組,比如我想將訂單按照城市進行分組,並統計出每個城市的訂單數量:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",count:{$sum:1}}})
我們將要分組的欄位傳遞給$group函式的_id
欄位,然後每當查到一個,就給count加1,這樣就可以統計出每個城市的訂單數量。
算術操作符
通過算術操作符我們可以對分組後的文件進行求和或者求平均數。比如我想計算每個城市訂單運費總和,如下:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",totalFreight:{$sum:"$freight"}}})
先按地址分組,再求和。這裡貼出部分查詢結果,如下:
{
"_id" : "HaiKou",
"totalFreight" : 20.0
}
{
"_id" : "HangZhou",
"totalFreight" : 10.0
}
也可以計算每個城市運費的平均數,如下:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",avgFreight:{$avg:"$freight"}}})
先按地址分組,然後再計算平均數。
極值操作符
極值操作符用來獲取分組後資料集的邊緣值,比如獲取每個城市最貴的運費,如下:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",maxFreight:{$max:"$freight"}}})
查詢每個城市最便宜的運費:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",minFreight:{$min:"$freight"}}})
按城市分組之後,獲取該城市第一個運費單:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",firstFreight:{$first:"$freight"}}})
獲取分組後的最後一個運費單:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",lastFreight:{$last:"$freight"}}})
資料操作符
$addToSet可以將分組後的某一個欄位放到一個數組中,但是重複的元素將只出現一次,而且元素加入到陣列中的順序是無規律的,比如將分組後的每個城市的運費放到一個數組中,如下:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",freights:{$addToSet:"$freight"}}})
重複的freight將不會被新增進來。
$push則對重複的資料不做限制,都可以新增進來,如下:
db.sang_collect.aggregate({$group:{_id:"$orderAddressL",freights:{$push:"$freight"}}})
$unwind
$unwind用來實現對文件的拆分,可以將文件中的值拆分為單獨的文件,比如我的資料如下:
{
"_id" : ObjectId("59f93c8b8523cfae4cf4ba86"),
"name" : "魯迅",
"books" : [
{
"name" : "吶喊",
"publisher" : "花城出版社"
},
{
"name" : "彷徨",
"publisher" : "南海出版出"
}
]
}
使用$unwind命令將其拆分為獨立文件,如下:
db.sang_books.aggregate({$unwind:"$books"})
拆分結果如下:
{
"_id" : ObjectId("59f93c8b8523cfae4cf4ba86"),
"name" : "魯迅",
"books" : {
"name" : "吶喊",
"publisher" : "花城出版社"
}
}
{
"_id" : ObjectId("59f93c8b8523cfae4cf4ba86"),
"name" : "魯迅",
"books" : {
"name" : "彷徨",
"publisher" : "南海出版出"
}
}
其他操作符
$sort操作可以對文件進行排序,如下:
db.sang_collect.aggregate({$sort:{orderAddressL:1}})
用法和我們之前介紹普通搜尋中的一致,可以按照存在的欄位排序,也可以按照重新命名的欄位排序,如下:
db.sang_collect.aggregate({$project:{oa:"$orderAddressL"}},{$sort:{oa:-1}})
1表示升序、-1表示降序。
$limit返回結果中的前n個文件,如下表示返回結果中的前三個文件:
db.sang_collect.aggregate({$project:{oa:"$orderAddressL"}},{$limit:3})
$skip表示跳過前n個文件,比如跳過前5個文件,如下:
db.sang_collect.aggregate({$project:{oa:"$orderAddressL"}},{$skip:5})
$skip的效率低,要慎用。
總結
在管道開始執行的階段儘可能過濾掉足夠多的資料,這樣做有兩個好處:1.只有從集合中直接查詢時才會使用索引,儘早執行過濾可以讓索引發揮作用;2.該過濾的資料過濾掉之後,也可以降低後面管道的執行壓力。另外,MongoDB不允許一個聚合操作佔用過多的記憶體,如果有一個聚合操作佔用了超過20%的記憶體,則會直接報錯。
好了,MongoDB中的管道操作符我們就先說到這裡,小夥伴們有問題歡迎留言討論。
參考資料:
1.《MongoDB權威指南第2版》
更多資料請關注公眾號: