使用mongodb在utc中存储日期时如何处理时区问题?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用mongodb在utc中存储日期时如何处理时区问题?相关的知识,希望对你有一定的参考价值。
我有一个mongodb集合,其中每个文档都有一些属性和一个utc时间戳。我需要从集合中提取数据并使用聚合框架,因为我使用集合中的数据在用户界面上显示一些图表。但是,我需要根据用户的时区进行聚合。假设我知道用户的时区(通过浏览器或其他方式传递请求),有没有办法使用聚合框架根据[客户端]时区进行聚合?
你要求的东西目前正在MongoDB issue SERVER-6310讨论。
我在a discussion thread的链接中找到了这个。
对于按日期进行的任何分组,这个问题很常见,包括SQL数据库和NoSQL数据库。事实上,我最近在RavenDB中解决了这个问题。有一个很好的描述问题和RavenDB解决方案here。
MongoDB问题讨论了一种解决方法,类似于我在上面的评论中所描述的。您可以预先计算您感兴趣的当地时间,然后按这些时间进行分组。
用这两种方法很难覆盖世界上的每个时区。您应该决定对您的用户群有意义的少数目标区域,例如我在RavenDB文章中描述的每个办公室方法。
更新:此问题已于2017年7月在MongoDB中解决(版本3.5.11)。解决方案在上面的第一个链接中描述,但简而言之,它们为聚合表达式中的日期引入了一种新的对象格式:{ date: <dateExpression>, timezone: <tzExpression> }
,允许您指定聚合时使用的时区。有关Mongo文档中的另一个示例,请参阅here。
除了Matt Johnson提到的SERVER-6310之外,另一个解决方法是使用$project
运算符在UTC时区中添加或减去“将时间”转移到正确的本地区域。事实证明,您可以以毫秒为单位添加或减去时间。
例如,假设我有一个名为orderTime
的Date字段。我想查询EDT。那是距UTC的-4小时。那是4 * 60 * 60 * 1000毫秒。
所以我会写下面的投影,以便在当地时间获取所有记录的day_ordered
:
db.table.aggregate(
{ $project : { orderTimeLocal : { $subtract : [ "$orderTime", 14400000] } } },
{ $project : { day_ordered : { $dayOfYear : "$orderTimeLocal" } } })
上面提出的每种方法都可以很好地完成,但是由于有一个新版本的mongodb,你可以在聚合框架中使用$let
,这样你就可以动态创建变量,从而避免在分组之前需要$project
。现在,您可以使用$let
创建一个变量,该变量将保存本地化时间,并在$group
运算符中使用它。
就像是:
db.test.aggregate([
{$group: {
_id: {
$let: {
vars: {
local_time: { $subtract: ["$date", 10800000]}
},
in: {
$concat: [{$substr: [{$year: "$$local_time"}, 0, 4]},
"-",
{$substr: [{$month: "$$local_time"}, 0, 2]},
"-",
{$substr: [{$dayOfMonth: "$$local_time"}, 0, 2]}]
}
}
},
count: {$sum: 1}
}
}])
请注意,在块/变量的定义中使用$let
,并且该块/变量的值是子表达式"in"
的返回值,其中使用了上面定义的变量。
我在mongoose plugin中找到了一个解决方案来规范化存储日期时区。
以上是关于使用mongodb在utc中存储日期时如何处理时区问题?的主要内容,如果未能解决你的问题,请参考以下文章