在mongodb

时间:2015-07-11 05:23:22

标签: node.js mongodb datetime mongodb-query aggregation-framework

我正在将在意大利使用的mongodb和nodejs中构建应用程序。意大利时区是+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:"$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个。但我们需要在7月11日显示2个tx,在7月10日显示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")

2 个答案:

答案 0 :(得分:4)

处理时区是一个“客户端”问题,因此您应该按时区偏移修改“查询”次数,以便在UI中允许“本地”时间选择等等。 UI显示也是如此,其中日期将以当地时间表示。

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

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 epoch以来的毫秒数。然后再简单地通过“添加”“时区偏移”来再次调整它,该时区偏移可能是正向小时,也可能是后面的负数,再次从时间值转换为有效的毫秒数。

然后舍入是一个简单的模$mod,以便从“一天中的毫秒数”中得到余数,然后将其删除以将调整后的日期精简到当天。

此处生成的数值很容易重新转换回日期,因为所有语言库“Date”对象都将epoch中的毫秒(或秒)作为构造函数参数。

所以再一次,这就是将数据响应修改为从“客户端”的“区域设置”出现,而不是关于如何存储数据。如果您想在应用程序中使用真正的位置,那么您可以在任何地方应用时区偏移的修改,就像上面所示。

-

实际上,您可以在聚合框架中创建日期,并使用更多日期数学。只需将纪元日期添加回转换日期:

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

答案 1 :(得分:2)

已添加mongo版本3.6时区中的

mongo doc

用时区提取日期部分的

表达式是

var item = 10;
delete item;
//Following will print 
console.log(item);

//The reason for upper is when we declare variable with var it is of 
//primitive data type and delete won't work.


item = 10;
delete item;
//Following will give reference error
console.log(item);

//The reason for upper is when we declare variable without var it is a 
//property of global 'window' object so delete work.

我们可以在获取日期部分时指定时区或偏移量

管道

{ date: <dateExpression>, timezone: <tzExpression> }

结果

> db.txs.aggregate([
...     { $group:{
...         _id: { 
...             day: {$dayOfMonth: {date :"$date", timezone : "Europe/Rome"}}, // timezone
...             month: {$month: {date : "$date", timezone : "+02:00"}}, //offset
...             year: {$year: {date : "$date", timezone : "+02:00"}} //offset
...         },
...         count:{$sum:1}
...     }}
... ])

timezone

列表