pymongo中group by的操作方法教程


Posted in Python onMarch 22, 2019

前言

使用 pymongo 进行 group by 操作有两种基本方式,他们都是 mongodb 的原生命令,于 Collection 对象上调用。

def aggregate(self, pipeline, **kwargs):
def group(self, key, condition, initial, reduce, finalize=None, **kwargs):

示例数据

演示用的数据为一个订单表,含有以下字段:

Order

_id: ObjectID
userid: int
itemid: int
amount: int
time:   string

主要任务为:

  • 统计某个时间区间内每个 userid 的订单数
  • 统计某个时间区间内每组 (userid, itemid) 共售出多少 amount

即分别为:单键分组和多键分组

aggregate

聚合操作只接受一个列表类型的参数 —— pipeline。其每一个元素都是一步操作(stage)。全部可用的 stage 可参见:

https://docs.mongodb.com/manual/meta/aggregation-quick-reference/#stages

注意 pipline 里面的 stage 是有序且可重复的,mongodb 会顺序执行,因此一定要记得把像 $match 这样的 stage 放前面。

单键分组

start_time = '2010-10-10 00:00:00'
end_time = '2010-10-10 23:59:59'

match = {
 'time': {
 '$gte': start_time,
 '$lte': end_time,
 }
}

groupby = 'userid'

group = {
 '_id': "$%s" % (groupby if groupby else None),
 'count': {'$sum': 1}

}

ret = collection.aggregate(
 [
 {'$match': match},
 {'$group': group},
 ]
)

>>> ret
[{'_id': 123, 'count': 500}, ...]

$group 指定了返回数据的格式,其中 _id 字段是分组的键。

多键分组

groupby = ['itemid', 'userid']

group = {
 '_id': {key: ('$%s' % key) for key in groupby} or {'None': '$None'},
 'count': {'$sum': '$amount'}
}

ret = collection.aggregate(
 [
 {'$match': match},
 {'$group': group},
 ]
)

>>> ret
[{'_id': {'itemid': 111, 'user_id': 123}, 'count': 100}, ...]

这里与单键分组的区别仅在于 _id 的类型,改成了一个字典,从而允许多键组合。

为了提高通用性,建议始终使用字典的格式。

另外,既然字符串和字典都可以做键,那么列表行不行呢?答案是不行,列表里的元素,(如 '$userid') 并不会被自动识别为字段,而是仅作一般字符串处理。

最后关于 aggregate 中可用的运算操作符,可参见:

https://docs.mongodb.com/manual/reference/operator/aggregation/#accumulators

如其中的 $addToSet 也是颇有用处,可以用来实现 “统计每个人都买过哪些 itemid” 这样的功能:

group = {
 '_id': {'userid': '$userid'},
 'dist_itemids': {'$addToSet': '$itemid'},
}

group

相较于 aggregate 的全能,group 是专门处理分组操作的一个命令,因此这个方法的参数也更明确,主要参数为:

  • key list, 分组的键
  • condition dict,过滤条件
  • initial dict,初始值
  • reduce string/bson.Code, js 的 reduce 函数

例:

key = ['userid', 'itemid']
condition = {
 'time': {
 '$gte': start_time,
 '$lte': end_time,
 }
}
initial = {'count': 0}
reducer = Code("""
 function(obj, prev) {
 prev.count = prev.count + obj.amount
 }
""")

ret = collection.group(key, condition, initial, reducer)

>>> ret
[{'userid': 110, 'itemid': 123, 'count': 500.0}, ...]

这里的分组数据聚合,是通过 reduce 函数实现的,这个函数与 python 的 reduce 不同,它不需要返回值,而是直接修改 prev 参数即可,这个参数会自动代入下一次调用。这可能是 js 的实现。

须注意的是 js 默认返回浮点数。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python break语句详解
Mar 11 Python
python使用PythonMagick将jpg图片转换成ico图片的方法
Mar 26 Python
Python 专题一 函数的基础知识
Mar 16 Python
python+selenium开发环境搭建图文教程
Aug 11 Python
python提取图像的名字*.jpg到txt文本的方法
May 10 Python
python logging重复记录日志问题的解决方法
Jul 12 Python
Python 实现「食行生鲜」签到领积分功能
Sep 26 Python
python 对key为时间的dict排序方法
Oct 17 Python
PyQt5 closeEvent关闭事件退出提示框原理解析
Jan 08 Python
Python3爬虫里关于识别微博宫格验证码的知识点详解
Jul 30 Python
python使用bs4爬取boss直聘静态页面
Oct 10 Python
使用Python爬虫爬取小红书完完整整的全过程
Jan 19 Python
Python常用特殊方法实例总结
Mar 22 #Python
pymongo中聚合查询的使用方法
Mar 22 #Python
OpenCV HSV颜色识别及HSV基本颜色分量范围
Mar 22 #Python
基于OpenCV python3实现证件照换背景的方法
Mar 22 #Python
详解Python给照片换底色(蓝底换红底)
Mar 22 #Python
详解python-图像处理(映射变换)
Mar 22 #Python
python中如何使用分步式进程计算详解
Mar 22 #Python
You might like
Body是什么,该怎么喝出咖啡里的口感
2021/03/03 咖啡文化
PHP 翻页 实例代码
2009/08/07 PHP
jQuery实现感应鼠标动画效果自动伸长的输入框实例
2015/02/24 Javascript
使用AngularJS创建单页应用的编程指引
2015/06/19 Javascript
解决js页面滚动效果scrollTop在FireFox与Chrome浏览器间的兼容问题的方法
2015/12/03 Javascript
javascript html实现网页版日历代码
2016/03/08 Javascript
javascript中arguments,callee,caller详解
2016/03/16 Javascript
浅谈JavaScript的全局变量与局部变量
2016/06/10 Javascript
详细解读Jquery各Ajax函数($.get(),$.post(),$.ajax(),$.getJSON())
2016/08/15 Javascript
bootstrap模态框嵌套、tabindex属性、去除阴影的示例代码
2017/10/17 Javascript
javascript Function函数理解与实战
2017/12/01 Javascript
在ES5与ES6环境下处理函数默认参数的实现方法
2018/05/13 Javascript
Nodejs异步回调之异常处理实例分析
2018/06/22 NodeJs
ios设备中angularjs无法改变页面title的解决方法
2018/09/13 Javascript
vue实现微信分享功能
2018/11/28 Javascript
node解析修改nginx配置文件操作实例分析
2019/11/06 Javascript
微信小程序实现锚点功能
2019/11/20 Javascript
d3.js 地铁轨道交通项目实战
2019/11/27 Javascript
Vue+Java 通过websocket实现服务器与客户端双向通信操作
2020/09/22 Javascript
vue 避免变量赋值后双向绑定的操作
2020/11/07 Javascript
Javascript中window.name属性详解
2020/11/19 Javascript
[05:53]敌法师的金色冠名ID"BurNIng",是传说,是荣耀
2020/07/11 DOTA
python 测试实现方法
2008/12/24 Python
Python代码实现KNN算法
2017/12/20 Python
Python自定义线程类简单示例
2018/03/23 Python
浅谈Python2、Python3相对路径、绝对路径导入方法
2018/06/22 Python
python寻找list中最大值、最小值并返回其所在位置的方法
2018/06/27 Python
python剪切视频与合并视频的实现
2020/03/03 Python
如何使用python记录室友的抖音在线时间
2020/06/29 Python
美国豪华时尚女性精品店:Kirna Zabête
2018/01/11 全球购物
LN-CC美国:伦敦时尚生活的缩影
2019/02/19 全球购物
教师党员批评与自我批评
2014/10/15 职场文书
教师党员群众路线教育实践活动心得体会
2014/11/04 职场文书
青岛海底世界导游词
2015/02/11 职场文书
从贫穷到富有,是知识技能和学习力的差别
2019/08/20 职场文书
详解OpenCV获取高动态范围(HDR)成像
2022/04/29 Python