0

我在 AppFog(前 Nodester)上运行一个博客风格的 Web 应用程序。它是用 NodeJS + Express 编写的,并使用 Mongoose 框架来持久化到 MongoDB。

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

为什么会有这个介绍?好吧,现在我的“帖子”显示在基本的“分页”可视化中,我的意思是它们只是从 mongo 中提取的,按日期降序排序,一次一页。这是一个片段:

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' 并显示类似“日记”的帖子,我的意思是:

第 1 页 => 2012/10/08:我显示 3 个帖子

第 2 页 => 2012/10/10:我显示 2 个帖子(2012/10/09 没有帖子,所以我不允许出现白页)

第 3 页 => 2012/10/11:35 个帖子等等……

我的想法是首先获取所有日期的列表并进行分组(并且可能计算每天的帖子),然后构建页面链接,当访问页面(日期)时,像上面一样查询,添加日期作为参数。

解决方案

  • 聚合框架非常适合,但我现在无法使用那个版本的 Mongo

  • 以某种方式使用 .group() ,但它在分片环境中不起作用的想法并不让我兴奋!:-(

  • 写一个 MAP-REDUCE!我认为这是正确的方法,但我无法想象应该如何编写 map() 和 reduce()。

你能帮我举个小例子吗?

谢谢

编辑

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

我的意思是,我会有 /archive/2012/10/01、/archive/2012/09/20 等 URL。

在每个页面中,有查询帖子的日期就足够了。但是我必须显示“NEXT”或“PREV”链接,所以我需要知道包含帖子的第二天或前一天是什么,如果有的话。也许我可以只查询日期大于或小于当前日期的帖子,并获取第一个日期?

4

1 回答 1

1

假设你有类似的东西:

{
"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 如下:

地图

它只是将日期作为键和帖子标题发出。您可以将标题更改为_id,这可能对您更有用。如果您存储日期的时间,您将只想使用日期(没有时间)作为键,否则 mongo 将按日期时间分组,而不仅仅是日期。在我的测试用例中,所有帖子都有相同的时间 00:00:00 所以没关系。

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

减少

它什么也不做,然后只是将键的所有值推送到数组,然后数组被包装在结果对象中,因为 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"
            ]
        }
    }
],
...
}

我希望这有帮助

于 2012-10-10T08:25:56.660 回答