在MongoDB中按date分组

我正在AppFog上运行一个博客式的Web应用程序(前Nodester)。 它是用NodeJS + Express编写的,使用Mongoose框架保存到MongoDB。

MongoDB是1.8版本,我不知道AppFog是否会升级到2.2。

为什么介绍这个? 那么,现在我的“post”显示在一个基本的“分页”的可视化,我的意思是他们只是从mongo拿起,按date降序sorting,一页一页。 这是一个片段:

Post .find({pubblicato:true}) .populate("commenti") .sort("-dataInserimento") .skip(offset) .limit(archivePageSize) .exec(function(err,docs) { var result = {}; result.postsArray = (!err) ? docs : []; result.currentPage = currentPage; result.pages = howManyPages; cb(null, result); }); 

现在,我的目标是GROUP BY'dataInserimento'和显示post就像一个“日记”,我的意思是:

第一页=> 2012/10/08:我显示3post

第二页=> 2012/10/10:我显示2post(2012/10/09没有post,所以我不允许一个白页)

第3页=> 2012/10/11:35post等等…

我的想法是首先获得所有date列表(也许每天计算post),然后build立页面链接,并且当页面(date)被访问时,像上面那样查询,添加date作为参数。

解决scheme

  • 汇总框架将是完美的,但我现在无法得到这个版本的Mongo

  • 以某种方式使用.group(),但它在分片环境中不起作用的想法不会激起我的兴趣! 🙁

  • 写MAP-REDUCE! 我认为这是正确的路要走,但我无法想象如何写map()和reduce()。

你能帮我一个小例子吗?

谢谢

编辑

peshkira的答案是正确的,但是,我不知道我是否需要这个。

我的意思是,我将拥有/ archive / 2012/10/01,/ archive / 2012/09/20等url。

在每个页面中,有足够的date来查询post。 但是,我必须显示“下一个”或“上一个”链接,所以我需要知道下一个或前一天包含post,如果有的话。 也许我可以查询date大于或小于当前date的post,并获得第一个date?

假设你有类似的东西:

 { "author" : "john doe", "title" : "Post 1", "article" : "test", "created" : ISODate("2012-02-17T00:00:00Z") } { "author" : "john doe", "title" : "Post 2", "article" : "foo", "created" : ISODate("2012-02-17T00:00:00Z") } { "author" : "john doe", "title" : "Post 3", "article" : "bar", "created" : ISODate("2012-02-18T00:00:00Z") } { "author" : "john doe", "title" : "Post 4", "article" : "foo bar", "created" : ISODate("2012-02-20T00:00:00Z") } { "author" : "john doe", "title" : "Post 5", "article" : "lol cat", "created" : ISODate("2012-02-20T00:00:00Z") } 

那么你可以使用map reduce如下:

地图

它只是发出date作为关键和职位的标题。 您可以将标题更改为_id,这可能对您更有用。 如果你存储date的时间,你只需要使用date(没有时间)作为关键,否则mongo将按date时间,而不仅仅是date。 在我的testing案例中,所有post都有相同的时间00:00:00,所以没关系。

 function map() { emit(this.created, this.title); } 

减less

它只做一个键的所有值,然后把数组包装在一个结果对象中,因为mongo不允许数组成为reduce函数的结果。

 function reduce(key, values) { var array = []; var res = {posts:array}; values.forEach(function (v) {res.posts.push(v);}); return res; } 

执行

使用db.runCommand({mapreduce: "posts", map: map, reduce: reduce, out: {inline: 1}})将会输出如下结果:

 { "results" : [ { "_id" : ISODate("2012-02-17T00:00:00Z"), "value" : { "posts" : [ "Post 2", "Post 1" ] } }, { "_id" : ISODate("2012-02-18T00:00:00Z"), "value" : "Post 3" }, { "_id" : ISODate("2012-02-20T00:00:00Z"), "value" : { "posts" : [ "Post 5", "Post 4" ] } } ], ... } 

我希望这有帮助

Interesting Posts