您好,登錄后才能下訂單哦!
前言
在使用mongo數據庫時,簡單的查詢基本上可以滿足大多數的業務場景,但是試想一下,如果要統計某一薦在指定的數據中出現了多少次該怎么查詢呢?笨的方法是使用find 將數據查詢出來,再使用count() 方法進行數據統計,這個場景還好,但是如果要求其中某個字段的和呢?是不是就非得遍歷出相應的數據然后再進行求和運算呢?
在mysql中我們經常會用到count、group by 等查詢,在mongodb中我們也可以使用聚合查詢。
假設有這樣的一組數據
價格
里面記錄了每種水果的價格,現在我要統計一下,各種水果在這張表中出現的次數,如果不用聚合查詢的話,思路應該是這樣,先把表中所有的數據都取出來,然后初始化一個字典,然后再遍歷每一行的數據,獲取它的fName ,然后再更新字典中的計數,這種方法的時間復雜度是O(N)的,如果數據量很大的話不是很好,下面來看一下使用聚合是怎么查詢的。
聚合查詢使用的是aggregate函數,它的參數是 pipeline 管道,管道的概念是用于將當前命令的輸出結果作為下一個命令的參數,管道是有順序的,比如通過第一個管道操作以后沒有符合的數據那么之后的管道操作也就不會有輸入,所以一定得要注意管道操作的順序。由于對于上述問題,我們要的是所的數據統計,所以這里就不需要$match了
from pymongo import MongoClient client = MongoClient(host=['%s:%s'%(mongoDBhost,mongoDBport)]) G_mongo = client[mongoDBname]['FruitPrice'] pipeline = [ {'$group': {'_id': "$fName", 'count': {'$sum': 1}}}, ] for i in G_mongo['test'].aggregate(pipeline): print i
數據大家可以自已構造,這里主要是看aggregate的用法。
得到的結果是
{u'count': 8, u'_id': u'banana'} {u'count': 9, u'_id': u'pear'} {u'count': 14, u'_id': u'apple'}
可以看到,一步操作就可以得到相應的統計了。
如果想要獲取價格在50以上的各種統計呢?
這時有pipeline應該再$group 之前加上$match 操作
pipeline = [ {'$match':{'price':{'$gte':50}}}, {'$group': {'_id': "$fName", 'count': {'$sum': 1}}}, ]
一定要注意順序
$match里的條件其實就和使用find函數里是一樣的。
下面重點來說說$group操作,group意為分組,指數據根據哪個字段進行分組,上面使用的{'$group': {'_id': "$fName", 'count': {'$sum': 1},_id為所要分的組,這里是以fName字段分的,后面的'count': {'$sum': 1},這里的$sum就是求和的意思,后面的值是1,也就是說每出現一次就加1,這樣就能達到計數的目的了,如果要計算價格 price 的和,那么這里就應該寫成這樣
{'$group': {'_id': "$fName", 'count': {'$sum': '$price'}}}
注意這里的字段要有$ 的,如果我想要求價格的平均值呢?也就是先要求出價格的總數,再除以商品的個數,但是這里有一個$avg 操作
pipeline = [ {'$match':{'price':{'$gte':50}}}, {'$group': {'_id': "$fName", 'avg': {'$avg': '$price'}}}, ]
得到的結果
{u'_id': u'banana', u'avg': 66.200000000000003}
{u'_id': u'pear', u'avg': 77.0}
{u'_id': u'apple', u'avg': 74.0}
類似于$ave的操作還有很多,比較常用的是$min(求最小值),$max(求最大值)
pipeline = [ {'$match':{'price':{'$gte':50}}}, {'$group': {'_id': "$fName", 'count':{'$sum':1}, 'priceAll':{'$sum':'$price'}, 'avg': {'$avg': '$price'}, 'min': {'$min':'$price'}, 'max': {'$max':'$price'} } }, ] for i in G_mongo['test'].aggregate(pipeline): print i
所有支持的操作可以參考官方文檔:group 支持的操作
以哪個字段進行分組時必須使用_id。
接下來看一下多鍵分組。
以上在使用group 進行分組查詢的時候,用到的_id都是單一字段,比如我的數據庫中有如下數據
帶用戶的數據
帶有一個user 字段了,那如果我要根據user和fName進行分組該如何操作呢?
這里可以傳一個字典進去
pipeline = [ {'$match':{'price':{'$gte':50}}}, {'$group': {'_id': {'fName':'$fName','user':'$user'}, 'count':{'$sum':1}, 'priceAll':{'$sum':'$price'}, 'avg': {'$avg': '$price'}, 'min': {'$min':'$price'}, 'max': {'$max':'$price'} } }, ] for i in G_mongo['test2'].aggregate(pipeline): print i
得到的結果如下:
{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}
{u'count': 2, u'avg': 88.0, u'min': 87, u'max': 89, u'_id': {u'user': u'yangyanxing', u'fName': u'banana'}, u'priceAll': 176}
{u'count': 2, u'avg': 70.0, u'min': 69, u'max': 71, u'_id': {u'user': u'yangyanxing', u'fName': u'pear'}, u'priceAll': 140}
{u'count': 2, u'avg': 65.5, u'min': 58, u'max': 73, u'_id': {u'user': u'fanjieying', u'fName': u'banana'}, u'priceAll': 131}
{u'count': 3, u'avg': 92.333333333333329, u'min': 86, u'max': 97, u'_id': {u'user': u'fantuan', u'fName': u'banana'}, u'priceAll': 277}
{u'count': 2, u'avg': 78.5, u'min': 73, u'max': 84, u'_id': {u'user': u'yangyanxing', u'fName': u'apple'}, u'priceAll': 157}
{u'count': 3, u'avg': 56.666666666666664, u'min': 51, u'max': 60, u'_id': {u'user': u'fantuan', u'fName': u'pear'}, u'priceAll': 170}
{u'count': 2, u'avg': 81.5, u'min': 73, u'max': 90, u'_id': {u'user': u'fanjieying', u'fName': u'apple'}, u'priceAll': 163}
{u'count': 2, u'avg': 69.5, u'min': 53, u'max': 86, u'_id': {u'user': u'fantuan', u'fName': u'apple'}, u'priceAll': 139}
這里的結果顯示出每個用戶買了哪個商品,一共花了多少錢,最大最小平均值等都可以一次性的展示了,如果要是使用for循環自已遍歷的話這種時間復雜度相當高。
這里只是簡單的說了下$group和$match 的用法,聚合查詢支持很多種操作(稱為stages),可以通官方文檔進行查看
pymongo 中pipeline中的stages
參考文章
pymongo 的 group by 方法
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。