在使用mongo數據庫時,簡單的查詢基本上可以滿足大多數的業務場景,但是試想一下,如果要統計某一薦在指定的數據中出現了多少次該怎么查詢呢?笨的方法是使用find
將數據查詢出來,再使用count()
方法進行數據統計,這個場景還好,但是如果要求其中某個字段的和呢?是不是就非得遍歷出相應的數據然后再進行求和運算呢?
在mysql中我們經常會用到count
、group by
等查詢,在mongodb中我們也可以使用聚合查詢。
里面記錄了每種水果的價格,現在我要統計一下,各種水果在這張表中出現的次數,如果不用聚合查詢的話,思路應該是這樣,先把表中所有的數據都取出來,然后初始化一個字典,然后再遍歷每一行的數據,獲取它的fName
,然后再更新字典中的計數,這種方法的時間復雜度是O(N)的,如果數據量很大的話不是很好,下面來看一下使用聚合是怎么查詢的。
聚合查詢使用的是aggregate
函數,它的參數是 pipeline
管道,管道的概念是用於將當前命令的輸出結果作為下一個命令的參數,管道是有順序的,比如通過第一個管道操作以后沒有符合的數據那么之后的管道操作也就不會有輸入,所以一定得要注意管道操作的順序。由於對於上述問題,我們要的是所的數據統計,所以這里就不需要$match
了
from pymongo import MongoClient |
數據大家可以自已構造,這里主要是看aggregate
的用法。
得到的結果是
1 |
{u'count': 8, u'_id': u'banana'} |
可以看到,一步操作就可以得到相應的統計了。
如果想要獲取價格在50以上的各種統計呢?
這時有pipeline應該再$group
之前加上$match
操作
1 |
pipeline = [ |
一定要注意順序
$match
里的條件其實就和使用find
函數里是一樣的。
下面重點來說說$group
操作,group意為分組,指數據根據哪個字段進行分組,上面使用的{'$group': {'_id': "$fName", 'count': {'$sum': 1}
,_id
為所要分的組,這里是以fName
字段分的,后面的'count': {'$sum': 1}
,這里的$sum
就是求和的意思,后面的值是1,也就是說每出現一次就加1,這樣就能達到計數的目的了,如果要計算價格 price
的和,那么這里就應該寫成這樣
1 |
{'$group': {'_id': "$fName", 'count': {'$sum': '$price'}}} |
注意這里的字段要有$
的,如果我想要求價格的平均值呢?也就是先要求出價格的總數,再除以商品的個數,但是這里有一個$avg
操作
1 |
pipeline = [ |
得到的結果
1 |
{u'_id': u'banana', u'avg': 66.200000000000003} |
類似於$ave
的操作還有很多,比較常用的是$min
(求最小值),$max
(求最大值)
1 |
pipeline = [ |
所有支持的操作可以參考官方文檔:group 支持的操作
以哪個字段進行分組時必須使用_id
。
接下來看一下多鍵分組。
以上在使用group
進行分組查詢的時候,用到的_id
都是單一字段,比如我的數據庫中有如下數據帶用戶的數據
帶有一個user
字段了,那如果我要根據user
和fName
進行分組該如何操作呢?
這里可以傳一個字典進去
1 |
pipeline = [ |
得到的結果如下:
1 |
{u'count': 1, u'avg': 93.0, u'min': 93, u'max': 93, u'_id': {u'user': u'fanjieying', u'fName': u'pear'}, u'priceAll': 93} |
這里的結果顯示出每個用戶買了哪個商品,一共花了多少錢,最大最小平均值等都可以一次性的展示了,如果要是使用for循環自已遍歷的話這種時間復雜度相當高。
這里只是簡單的說了下$group
和$match
的用法,聚合查詢支持很多種操作(稱為stages
),可以通官方文檔進行查看
pymongo 中pipeline中的stages