我正在mongodb和nodejs中构建将在意大利使用的应用程序。意大利时区为+02:00。这意味着,如果有人在7月11日的01:am保存了一些数据,则将其保存为7月10日的11:00 pm,作为mongo在UTC中保存的日期。我们需要显示按日期排列的TX计数。所以我按日期进行了分组查询。但它显示前一天的TX。为此应采取的解决方法。
> db.txs.insert({txid:"1",date : new Date("2015-07-11T01:00:00+02:00")}) > db.txs.insert({txid:"2",date : new Date("2015-07-11T05:00:00+02:00")}) > db.txs.insert({txid:"3",date : new Date("2015-07-10T21:00:00+02:00")}) > db.txs.find().pretty() { "_id" : ObjectId("55a0a55499c6740f3dfe14e4"), "txid" : "1", "date" : ISODate("2015-07-10T23:00:00Z") } { "_id" : ObjectId("55a0a55599c6740f3dfe14e5"), "txid" : "2", "date" : ISODate("2015-07-11T03:00:00Z") } { "_id" : ObjectId("55a0a55699c6740f3dfe14e6"), "txid" : "3", "date" : ISODate("2015-07-10T19:00:00Z") } > db.txs.aggregate([ { $group:{ _id: { day:{$dayOfMonth:"$date"}, month:{$month:"$date"}, year:{$year:"$date"} }, count:{$sum:1} }} ]) { "_id" : { "day" : 11, "month" : 7, "year" : 2015 }, "count" : 1 } { "_id" : { "day" : 10, "month" : 7, "year" : 2015 }, "count" : 2 }
它显示7月10日为2 tx,7月11日为1 tx。但是我们需要显示7月11日的2吨和7月10日的1吨。
实际上是7月11日在意大利
db.txs.insert({txid:"1",date : new Date("2015-07-11T01:00:00+02:00")})
发生了,但mongo将日期存储为:
ISODate("2015-07-10T23:00:00Z")
处理时区是一个“客户端”问题,因此您应按时区偏移量修改“查询”时间,以允许在UI等中选择“本地”时间。UI显示也是如此,其中日期将以当地时间表示。
同样适用于您的聚集原理。只需按时区偏移量进行调整即可。应用日期数学而不是使用日期聚合运算符:
var tzOffset = 2; db.txs.aggregate([ { "$group": { "_id": { "$subtract": [ { "$add": [ { "$subtract": [ "$date", new Date("1970-01-01") ] }, tzOffset * 1000 * 60 * 60 ]}, { "$mod": [ { "$add": [ { "$subtract": [ "$date", new Date("1970-01-01") ] }, tzOffset * 1000 * 60 * 60 ]}, 1000 * 60 * 60 * 24 ]} ] }, "count": { "$sum": 1 } }} ]).forEach(function(doc){ printjson({ "_id": new Date(doc._id), "count": doc.count }) });
这给你:
{ "_id" : ISODate("2015-07-10T00:00:00Z"), "count" : 1 } { "_id" : ISODate("2015-07-11T00:00:00Z"), "count" : 2 }
因此,当您将 $subtract 一个BSON日期与另一个日期进行比较时,结果是自unix纪元以来的毫秒数。然后简单地通过“增加”正时或负的“时区偏移量”来再次调整此值,再次将其从时间值转换为有效毫秒数。
$subtract
然后,舍入是一个简单的模 $mod ,可以从“一天中的毫秒数” 中获取余数,然后将其删除以将调整后的日期仅舍入到当前日期。
$mod
由于所有语言库“ Date”对象都以纪元为毫秒(或秒)作为构造函数参数,因此这里生成的数值很容易重新转换为日期。
同样,这都是关于修改数据响应以从“客户端”的“区域设置”呈现的,而不是更改数据的存储方式。如果您希望在应用程序中使用真实的本地性,则可以像上面介绍的那样,对时区偏移量进行修改。
-
实际上,您可以在聚合框架本身中创建日期,并添加一些日期数学。只需将纪元日期添加回转换后的日期即可:
db.txs.aggregate([ { "$group": { "_id": { "$add": [ { "$subtract": [ { "$add": [ { "$subtract": [ "$date", new Date(0) ] }, tzOffset * 1000 * 60 * 60 ]}, { "$mod": [ { "$add": [ { "$subtract": [ "$date", new Date(0) ] }, tzOffset * 1000 * 60 * 60 ]}, 1000 * 60 * 60 * 24 ]} ]}, new Date(0); ] }, "count": { "$sum": 1 } }} ])