聚集在当地时区mongodb [英] Aggregating in local timezone in mongodb

查看:266
本文介绍了聚集在当地时区mongodb的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在意大利使用的mongodb和nodej中构建应用程序。意大利时区是+02:00。这意味着如果有人在7月11日上午01点之前保存一些数据,那么将保存为7月10日晚上11点,因为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: $日期},
年:{$ year:$ date}
},
计数:{$ sum:1}
}}
])

{_id:{day:11,month:7,year:2015},count:1}
{_id天:10,月:7,年:2015},计数:2}



在7月10日和7月11日的1号显示2 txs。但是,7月10日我们需要显示2 txs的11月和1 tx。



实际上是在意大利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显示在当地时间也是如此。



同样适用于您的聚合原则。只需按时区偏移进行调整。应用日期数学而不是使用日期聚合运算符:

  var tzOffset = 2; 

db.txs.aggregate([
{$ group:{
_id:{
$ subtract:[
{ $ add:[
{$ subtract:[$ date,new Date(1970-01-01)]},
tzOffset * 1000 * 60 * 60

$ b {$ mod:[
{$ add:[
{$ subtract:[$ date,new Date 01)]},
tzOffset * 1000 * 60 * 60
]},
1000 * 60 * 60 * 24
]}
]
},
count:{$ sum:1}
}}
])forEach(function(doc){
printjson({_id日期(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纪元以来的毫秒数。只需再次通过添加时差抵消即可获得前进时间,或者向后转换为负值,再次从时间值转换为有效的毫秒。



舍入是一个简单的模数 $ mod ,以从每天的毫秒数中获取余额,并将其删除,以将调整后的日期缩小到当天。



由于所有语言库Date对象以时间为单位的毫秒(或秒)作为构造函数参数,所以在此处生成的数值很容易重新转换为日期。



所以再一次,这是关于修改从客户端的locale显示的数据响应,而不是关于数据的存储方式。如果您想要在应用程序中使用真实的位置,那么您可以随时随地对时区偏移进行修改,如上所述。



-



实际上,您可以在聚合框架本身创建日期,并提供更多的日期数学。只需将时间日期添加到转换日期:

  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
]}
]},
新日期(0);
]
},
count:{$ sum:1}
}}
])


I am building application in mongodb and nodejs that will be used in Italy . Italy timezone is +02:00 . This means if any one saving some data at 01:am of 11 July then it will be saved as 11:00 pm of 10 July as mongo saves date in UTC. We need to show date wise tx count. So I made group by query on date. But it shows that tx in previous day. What should be workaround for this.

> 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 }

It shows 2 txs in 10th of July and 1 in 11 July . But we need to show 2 txs for 11 july and 1 tx for 10 July.

It was actually 11 July in Italy when

db.txs.insert({txid:"1",date : new Date("2015-07-11T01:00:00+02:00")})

took place but mongo stored date as:

ISODate("2015-07-10T23:00:00Z")

解决方案

Dealing with timezones is a "client" issue, so you shoud be modifying "query" times by the timezone offset in order to allow "local" time selection in UI and so forth. The same goes for UI display where the dates are to be represented in the local time.

And the same applies to your arggregation principle. Just adjust by the timezone offset. Appply date math instead of using the date aggregation operators:

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 }) 
});

Which gives you:

{ "_id" : ISODate("2015-07-10T00:00:00Z"), "count" : 1 }
{ "_id" : ISODate("2015-07-11T00:00:00Z"), "count" : 2 }

So when you $subtract one BSON date from another the result is the number of milliseconds since unix epoch. Simply then adjust this again by "adding" the "timezone offset" being either possitive for forward hours or negative for behind, again converted to valid millseconds from the time value.

The rounding then is a simple modulo $mod to get the remainder from the "number of milliseconds in a day" and remove that to round out the adjusted date to the current day only.

The resulting numeric values here are easily re-cast back into dates since all language library "Date" objects take the milliseconds ( or seconds ) from epoch as a constructor argument.

So again, this is all about modifying the data response to present from the "locale" of your "client" and not about channging how the data is stored. If you want true locality in your application then you apply modifications for timezone offsets everywhere, just as is presented above.

--

Actually you can just create the date in the aggregation framework itself, with a little more date math. Simply add the epoch date back to the converted 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 }
    }}
])

这篇关于聚集在当地时区mongodb的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆