Javascript Mongodb组收集条目(根据时间戳,按天),性能优化

Javascript Mongodb组收集条目(根据时间戳,按天),性能优化,javascript,performance,mongodb,Javascript,Performance,Mongodb,我有一个使用mongodb存储数据的节点web应用程序。我有一个邮件集合,看起来像: [ { "message": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut", "pubDate": "2014-01-16T14:15:33.792Z", "pubTimezone": "America/Tijuana" "id":

我有一个使用mongodb存储数据的节点web应用程序。我有一个邮件集合,看起来像:

[
  {
    "message": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut",
    "pubDate": "2014-01-16T14:15:33.792Z",
    "pubTimezone": "America/Tijuana"
    "id": "a9baa2f0-7eb8-11e3-b732-0b0c79e81098"
  },
  {
    "message": "labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco",
    "pubDate": "2014-01-16T14:01:24.198Z",
    "pubTimezone": "America/Tijuana"
    "id": "af550860-7eb6-11e3-b732-0b0c79e81098"
  },
  {
    "message": "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in",
    "pubDate": "2014-01-17T01:12:27.277Z",
    "pubTimezone": "America/Tijuana"
    "id": "6dff53d0-7f14-11e3-b732-0b0c79e81098"
  },
  {
    "message": "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat",
    "pubDate": "2014-01-17T01:10:17.249Z",
    "pubTimezone": "America/Tijuana"
    "id": "207ea110-7f14-11e3-b732-0b0c79e81098"
  }
...
]
我想运行一个查询,根据pubDate时间戳按天分组,结果是:

[
  {
    "items":[
      {
        "message":"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut",
        "pubDate":"2014-01-16T14:15:33.792Z",
        "pubTimezone": "America/Tijuana"
        "id":"a9baa2f0-7eb8-11e3-b732-0b0c79e81098"
      },
      {
        "message":"labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco",
        "pubDate":"2014-01-16T14:01:24.198Z",
        "pubTimezone": "America/Tijuana"
        "id":"af550860-7eb6-11e3-b732-0b0c79e81098"
      }
    ],
    "day":"2014-01-16T00:00:00.000Z"
  },
  {
    "items":[
      {
        "message":"laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in",
        "pubDate":"2014-01-17T01:12:27.277Z",
        "pubTimezone": "America/Tijuana"
        "id":"6dff53d0-7f14-11e3-b732-0b0c79e81098"
      },
      {
        "message":"voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat",
        "pubDate":"2014-01-17T01:10:17.249Z",
        "pubTimezone": "America/Tijuana"
        "id":"207ea110-7f14-11e3-b732-0b0c79e81098"
      }
    ],
    "day":"2014-01-17T00:00:00.000Z"
  }
...
]
按相反的日期顺序,必须使用时区来计算日期。 结果每页50页。
请注意,有些天没有创建任何项目,并且数据库中的发布日期都是ISODate格式

我已经阅读了一些关于分组的帖子,但是它们似乎都在做求和/计数任务,而不是按照我正在寻找的输出格式将所有结果按天分组。我也读过一些关于聚合框架和MapReduce的博客,但进展不大

如果可以在同一个查询中获得total_消息和total_天,那就太好了,尽管当我得到结果时,我总是可以在代码中这样做

我让我的web应用程序工作的方式是,它以日期描述的顺序提取所有消息,然后在代码中按天对它们进行排序,性能非常糟糕,因此我希望找到一种方法来处理数据库中的数据


非常感谢您的指导和/或帮助。

如果您的日期是ISODate格式,则应将其保存为数据库中的此类型。以下行显示类型为字符串:

    "pubDate": "2014-01-16T14:15:33.792Z",
应该是这样的:

{
  "message" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut",
  "pubDate" : ISODate("2014-01-16T14:15:33.792Z"),
  "pubTimezone" : "America/Tijuana",
  "id" : "a9baa2f0-7eb8-11e3-b732-0b0c79e81098"
}
在第一个方案中,假设您可以将字符串更改为ISODate类型。 然后,您可以使用聚合框架函数提取有关日期的信息。MongoDB将返回与GMT-0值对应的年、月和日的值。我认为这是你想要的,但如果不是,请参阅第二种解决方案

然后,运行聚合查询应该可以满足您的需求:

db.mycollection.aggregate([{"$project":{year:{"$year":"$pubDate"},month:{"$month":"$pubDate"},day:{"$dayOfMonth":"$pubDate"},"item":{"message":"$message","pubDate":"$pubDate","pubTimezone":"$pubTimezone","id":"$id"}}},{"$group":{"_id":{"year":"$year","month":"$month","day":"$day"},"items":{"$push":"$item"},"count":{"$sum":1}}}]).result

[
{
    "_id" : {
        "year" : 2014,
        "month" : 1,
        "day" : 17
    },
    "items" : [
        {
            "message" : "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in",
            "pubDate" : ISODate("2014-01-17T01:12:27.277Z"),
            "pubTimezone" : "America/Tijuana",
            "id" : "6dff53d0-7f14-11e3-b732-0b0c79e81098"
        },
        {
            "message" : "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat",
            "pubDate" : ISODate("2014-01-17T01:10:17.249Z"),
            "pubTimezone" : "America/Tijuana",
            "id" : "207ea110-7f14-11e3-b732-0b0c79e81098"
        }
    ],
    "count" : 2
},
{
    "_id" : {
        "year" : 2014,
        "month" : 1,
        "day" : 16
    },
    "items" : [
        {
            "message" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut",
            "pubDate" : ISODate("2014-01-16T14:15:33.792Z"),
            "pubTimezone" : "America/Tijuana",
            "id" : "a9baa2f0-7eb8-11e3-b732-0b0c79e81098"
        },
        {
            "message" : "labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco",
            "pubDate" : ISODate("2014-01-16T14:01:24.198Z"),
            "pubTimezone" : "America/Tijuana",
            "id" : "af550860-7eb6-11e3-b732-0b0c79e81098"
        }
    ],
    "count" : 2
}
]
请注意,只能对一个字段列表进行分组。这意味着,您可以获得每天的文档数,使用聚合返回的文档数作为天数,但您需要计算应用程序中的消息总数,并遍历文档

第二种解决方案适用于不能使用ISODate类型或希望在非GMT时间存储数据的情况。 在该解决方案中,计算一个附加字段,该字段表示要聚合的日期。例如,您可以使用附加的“日期”字段创建文档:

{
  "message" : "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut",
  "pubDate" :"2014-01-16T14:15:33.792Z",
  "pubTimezone" : "America/Tijuana",
  "date" : "2014-01-16"),
  "id" : "a9baa2f0-7eb8-11e3-b732-0b0c79e81098"
}
然后编写一个类似的聚合查询,但在$group子句中使用'date'作为您的'\u id'。 使用预先计算的字段进行聚合的优点是速度更快,但也可以让您执行简单的操作

find({"date":"2014-01-16"})
查询以检索文档子集(如果需要)。
与聚合框架相比,使用简单的find()命令的优点是后者需要在返回结果之前完成所有处理。find()命令将开始批量返回结果,因此,如果要将结果分页给用户,速度会更快。

求和是将两个整数相加。计数是指为找到的每个项目增加一个计数器。您要做的是将项目堆叠在一起:不同的操作,相同的原则。看看$push聚合操作符。顺便说一句,我不确定您是否能够在聚合管道中以您希望的方式处理时区字段,您可能必须使用map/reduce来构建更复杂(尽管速度较慢)的分组逻辑。