mongodb 分组 topN

      来源:https://groups.google.com/forum/#!topic/mongodb-user/Rjv6lyUCe1s

【摘要】

        MongoDB 对于 TopN 功能的需求使用其 shell 脚本来实现有些复杂,而集算器 SPL 语言,则因其离散性、灵活性恰好能弥补 MongoDB 实现方面的不足。若想了解更多,请前往乾学院:mongodb 分组 topN!

      在统计应用项目中,我们经常会遇到这样的需求:将大量的对象进行排序,然后只需要取出前 N 名作为排行榜的数据,这就是 TopN 算法。mongodb作为nosql数据库的典型代表,能够存储海量数据,在使用过程中也经常会遇到TopN的需求,例如将需要字段的最新数据从mongodb中获取出来。下面就使用集算器 SPL 语言操作,通过案例分析如何实现上述功能。

      Collection last3有两个字段:variabletimestamp,这里首先按variable分组,然后在每组文档中选出timestamp最晚的3个,最后再从这些文档中找到timestamp最早的1个。

      last3的部分数据如下:

{"_id" :   ObjectId("54f69645e4b077ed8d997857"),"variable" :   "A", "timestamp" : ISODate("1995-01-01T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997856"),"variable" :   "A", "timestamp" : ISODate("1995-01-02T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997855"),"variable" :   "A", "timestamp" : ISODate("1995-01-03T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997854"),"variable" :   "B", "timestamp" : ISODate("1995-01-02T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997853"),"variable" :   "B", "timestamp" : ISODate("1995-01-01T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997852"),"variable" :   "B", "timestamp" : ISODate("1994-01-03T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997851"),"variable" :   "C", "timestamp" : ISODate("1994-01-03T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997850"),"variable" :   "C", "timestamp" : ISODate("1994-01-02T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997858"),"variable" :   "C", "timestamp" : ISODate("1994-01-01T00:00:00Z")}

{"_id" :   ObjectId("54f69645e4b077ed8d997859"),"variable" :   "C", "timestamp" : ISODate("1993-01-01T00:00:00Z")}

集算器代码:

A B
1 =mongo_open("mongodb://localhost:27017/local?user=test&password=test")
2 =mongo_shell(A1,"last3.find(,{_id:0};{variable:1})")
3 for A2;variable =A3.top(3;-timestamp)
4 =@|B3
5 =B4.minp(~.timestamp)
6 =mongo_close(A1)

      A1:连接MongoDB,连接字格式为mongo://ip:port/db?arg=value&…

      A2:使用find函数从MongoDB中取数并排序,形成游标。collectoinlast3,过滤条件是空,取出_id之外的所有字段,并按variable排序。

      A3:循环从游标读数,每次取variable字段相同的一组文档。A3循环的的作用范围是缩进的B3B4,在这个范围中可以用A3来引用循环变量,这里A3是内存数据,在调试方式下可以查看某次取数的结果如下:

variable timestamp
C 1994-01-03 08:00:00
C 1994-01-02 08:00:00
C 1994-01-01 08:00:00
C 1993-01-01 08:00:00

      B3:选出本组文档中timestamp最晚(大)的3个。

      B4:B3不断地追加到B4中。B4如下:

variable timestamp
A 1995-01-03 08:00:00
A 1995-01-02 08:00:00
A 1995-01-01 08:00:00
B 1995-01-02 08:00:00
B 1995-01-01 08:00:00
B 1994-01-03 08:00:00
C 1994-01-03 08:00:00
C 1994-01-02 08:00:00
C 1994-01-01 08:00:00

      A5:选出B4timstamp最早(小)的那个文档,即:

variable timestamp
C 1994-01-01 08:00:00

      A6:关闭mongodb连接。

      实现类似MongodbtopN的需求,使用SPL语言能简化mongodb shell的实现,相对mongodb脚本容易多了。