Python操作mongodb的group by操作(pymongo实现)

正如江湖传言,mongodb是nosql数据库中对关系查询支持最好的。这里介绍其用python语言的groupby操作(用pymongo实现)。

首先说一下这项工作的背景,线上有一个mongo数据库,名为test。其中,有两个我们要关心的集合,一个是paper_info,另一个是aff_info,下面分别介绍:
paper_info中存放的是一些论文信息,比如论文的Authors,会议或期刊名称Journal,还有期刊的分级Rank等。下面该集合中的一个doc,可以作为一个例子。

{
    _id: ObjectId("5242fd5e02387746099f9cc5"),
    Rank: "unknow",
    Title: "Global Convergence of Inexact Reduced SQP Methods",
    Journal: "Universität Trier, Mathematik/Informatik, Forschungsbericht",
    Publtype: "informal publication",
    Year: "1995",
    Volume: "95-20",
    Key: "tr/trier/MI95-20",
    Authors: [
            "Heidi Jäger",
            "Ekkehard W. Sachs"
        ],
    Authors_Low_Case: [
            "heidi jäger",
            "ekkehard w. sachs"
        ],
    Type: "article",
    Id: "62"
}
aff_info中存放的是一些单位的信息,其中包含属于该单位的学者列表。下面该集合中的一个doc,可以作为例子理解。
{
    _id: ObjectId("523efb2b02387725a9fdf38b"),
    Stat:"A",
    Scholars: [
            "Hyong-Jun La",
            "Thura Lin Naing",
            "Akshay Krishnamurthy",
            "J.-S. Roger",
            "Tracy Xiaoxiao Wang",
            "Hoi-Sheung Wilson",
            "Jeffrey Herman",
            "Kenneth Keller"
        ],
    Id: 1794,
    Name: "University of California"
}
下面,根据上面两个库中的信息,我们想统计一下各个单位中的论文发表情况,简单的说就是各单位每年发了各类文章各多少篇。这里要用到mongodb的group操作,也就是传统的关系数据库中的group by。

pymongodb的官方文档中,对于group是这样说明的。
The group() method provides some of the same functionality as SQL’s GROUP BY. Simpler than a map reduce you need to provide a key to group by, an initial value for the aggregation and a reduce function.
Note:Doesn’t work with sharded MongoDB configurations, use aggregation or map/reduce instead of group().
Here we are doing a simple group and count of the occurrences x values:

>>> reducer = Code("""
                   ...                function(obj, prev){
                   ...                  prev.count++;
                   ...                }
                   ...                """)
>>> from bson.son import SON
>>> results = db.things.group(key={"x":1}, condition={}, initial={"count": 0}, reduce=reducer)
>>> for doc in results:
...   print doc
{u'count': 1.0, u'x': 1.0}
{u'count': 2.0, u'x': 2.0}
{u'count': 1.0, u'x': 3.0}
实际上,简单说,group函数group(key,condition,initial,reduce)完成的功能是:对集合中所有符合condition条件的记录,根据key指定的字段进行分组(也就是关系数据库中的group by)。对于一组中的各个记录,都作为reduce函数的第一个参数执行reduce函数。最后的结果是一个数组,其中的每一个元素是根据一组数据产生一条记录,也就是doc(也可以理解成字典吧!?)。该记录中包含key参数中指定的字段和initial中指定的字段。为了理解group,还要理解reduce函数的第二个参数,它可以理解成是对initial中指定的字段的引用,对每一组内的所有记录可见。到这里就不难理解上面的例子中为什么可以对prev.count++了吧?!
下面的源码是将论文的统计信息更新到aff_info集合中的Stat字段:
#!/usr/bin/python
#-*-coding:utf-8-*-
import pymongo
import string
def compute_stat():
    con=pymongo.Connection("10.77.20.xx",27017)
    test=con.test
    paper_info=test.paper_info
    affiliation=test.aff_info
    
    aff_cursor=affiliation.find()
    for d in aff_cursor:
        schs=d["scholars"]
        func='''
                function(obj,prev)
                {
                    prev.count++;
                }
        '''
        stat=paper_info.group({"Year":-1,"Rank":1},{"Authors":{"$in":schs}},{"count":0},func)
        def paixu(s):
            return string.atoi(s["Year"])
        stat_sorted=sorted(stat,reverse=True,key=paixu)
        d["Stat"]=stat_sorted
        affiliation.save(d)
    return True

最后,关于代码中的两点还是要废话一下:

(1)group函数中的condition参数{"Authors":{"$in":schs}}:这里的Authors字段的值是一个数组,schs也是一个数组。这一个条件选中的实际是Authors数组中的任何一个元素出现在schs中的记录。

(2)排序,关于sorted这里传递了一个函数参数,详见代码。

大笑


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值