如何更新ISO日期的收集和增量时间

时间:2015-08-01 10:16:41

标签: mongodb

我的收藏文件中有ISO日期。

"start" : ISODate("2015-07-25T17:35:00Z"),
"end" : ISODate("2015-09-01T23:59:00Z"),

目前他们在GMT + 0,我需要他们是GMT +8。因此,我需要在现有字段中添加8小时。我如何通过mongodb查询执行此操作?

建议表示赞赏。

更新了代码段

var offset = 8,
bulk = db.collection.initializeUnorderedBulkOp(),
count = 0;

db.collection.find().forEach(doc) {
bulk.find({ "_id": doc._id }).updateOne({
   "$set": { “startDateTime": new Date(
       doc.startDateTime.valueOf() + ( 1000 * 60 * 60 * offset )
   ) }
});
count++;

if ( count % 1000 == 0 ) {
    bulk.execute();
    bulk = db.collection.initializeUnorderedBulkOp();
}
});

if ( count % 1000 !=0 )
    bulk.execute();

2 个答案:

答案 0 :(得分:2)

默认情况下,MongoDB将所有DateTime存储为UTC。

有两种方法可以做到这一点:

应用方(推荐)

从数据库中提取startend时,请使用您选择的语言将其从UTC更改为本地日期时间。

要查看Python中的一个好例子,请查看this answer

数据库方面(不推荐)

另一种选择是编写一个mongodb查询,它会像您最初想要的那样为startend增加8小时。然而,这会将时间设置为UTC,但将来会设置为8小时,对于其他开发人员和解析应用程序端时则变得不合逻辑。

这需要根据文档中的其他值进行更新,因此您必须以described here的形式遍历每个文档。

答案 1 :(得分:2)

我全心全意地与Ewan提供的答案进行协商,因为您确实应该将所有时间保留在UTC的数据库中。所有的情绪都是正确的。只是通过实际例子真正增加了这一点。

作为一个工作示例,我们假设我有两个人使用这些数据,一个在纽约,另一个在悉尼,分别是UTC-5UTC+10。现在考虑以下数据:

{ "date": ISODate("2015-08-01T04:40:03.389Z") }

基于此,这是实际"事件"发生了。从悉尼用户的角度来看,该事件发生在8月1日整天,在纽约仍然发生在7月31日。

但是,如果我构建一个"本地化的"悉尼时间如下,UTC考虑仍然正确:

 new Date("2015/08/01")
 ISODate("2015-07-31T14:00:00Z")

这通过从本地时区转换为UTC来强制执行时差。因此,本地化日期将选择UTC中的正确值。因此,悉尼用户在8月1日开始时的所有时间都包括从7月31日下午2点开始的所有时间,并且类似地调整到范围选择的结束日期。对于UTC中的数据,来自客户端的此断言正确,并且对于它们所选择的数据处于预期范围内。

如果你是"聚合"给定日期的结果,然后你建立时间差"数学进入表达。因此,对于UTC + 10,您可以这样做:

var offset = 10;

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$subtract": [
                { "$add": [
                    {"$subtract": [ "$date", new Date(0)]},
                    offset * 1000 * 60 * 60 
                ]},
                { "$mod": [
                    { "$add": [ 
                        { "$subtract": [ "$date", new Date(0) ] },
                        offset * 1000 * 60 * 60
                    ]},
                    1000 * 60 * 60 * 24
                ]}
            ]
        },
        "count": { "$sum": 1 }
   }}

然后采用"偏移"报告"日期"时考虑的区域设置到正在查看数据的客户端。所以在"调整后的日期"导致不同的一天,如8月31日将通过此调整汇总到正确的分组。

因为您可以从不同时区的人员中很好地使用您的数据,这正是您应该以UTC格式保存日期数据的原因。客户将完成工作,或者您可以根据需要进行相应调整。

简而言之:

  • 客户:以当地时间构建,以UTC格式发送

  • 服务器:提供TZ偏移并在返回时从UTC调整为本地

以正确的格式保留日期,并使用此处描述的方法进行报告。

但如果你犯了错误

但是,如果您在构建数据方面犯了错误,并且所有时间实际上都是"本地"时间但以UTC重复,即:

ISODate("2015-08-01T11:10:43.569Z") // actually meant to be 11am in UTC+10 :(

它应该在哪里:

ISODate("2015-08-01T01:10:43.569Z") // This is 11am UTC+10 :)

然后你会按如下方式更正:

var offset = 10,
    bulk = db.collection.initializeUnorderedBulkOp(),
    count = 0;

db.collection.find().forEach(doc) {
    bulk.find({ "_id": doc._id }).updateOne({
       "$set": { "date": new Date(
           doc.date.valueOf() - ( 1000 * 60 * 60 * offset )
       ) }
    });
    count++;

    if ( count % 1000 == 0 ) {
        bulk.execute();
        bulk = db.collection.initializeUnorderedBulkOp();
    }
});

if ( count % 1000 !=0 )
    bulk.execute();

阅读每个文档以获得" date"值并相应地调整并将更新的日期值发送回文档。