Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb 如何在不同时区按年-月-日进行聚合_Mongodb_Aggregation Framework_Mongo Java - Fatal编程技术网

Mongodb 如何在不同时区按年-月-日进行聚合

Mongodb 如何在不同时区按年-月-日进行聚合,mongodb,aggregation-framework,mongo-java,Mongodb,Aggregation Framework,Mongo Java,我有一个MongoDB,它将日期对象存储在UTC中。嗯,我想在不同的时区(CET)中按年、月、日进行聚合 这样做对于UTC来说效果很好: BasicDBObject group_id = new BasicDBObject("_id", new BasicDBObject("year", new BasicDBObject("$year", "$tDate")). append("month", new BasicDBObject("$month", "$

我有一个MongoDB,它将日期对象存储在UTC中。嗯,我想在不同的时区(CET)中按年、月、日进行聚合

这样做对于UTC来说效果很好:

    BasicDBObject group_id = new BasicDBObject("_id", new BasicDBObject("year", new BasicDBObject("$year", "$tDate")).
                append("month", new BasicDBObject("$month", "$tDate")).
                append("day", new BasicDBObject("$dayOfMonth", "$tDate")).
                append("customer", "$customer"));

    BasicDBObject groupFields = group_id.
            append("eventCnt", new BasicDBObject("$sum", "$eventCnt")); 

    BasicDBObject group = new BasicDBObject("$group", groupFields);
或者,如果使用命令行(未测试,我只测试了java版本):

如何在聚合框架内将这些日期转换为CET

例如,“2013-09-16 23:45:00 UTC”是“2013-09-17 CET 00:45:00”,这是不同的一天。


<?php
    date_default_timezone_set('Asia/Karachi');
    $date=getdate(date("U"));
    $day = $date['mday'];
    $month =$date['mon'];
    $year = $date['year'];
    $currentDate = $year.'-'.$month.'-'.$day;
?>

我不是CET及其与UTC关系方面的专家,但以下代码(对于shell)应该对MongoDB日期类型进行适当转换(增加一小时):

db.dates.aggregate(
  {$project: {"tDate":{$add: ["$tDate", 60*60*1000]}, "eventCount":1, "customer":1}}
)

如果在管道的其余部分之前运行该项目命令,那么搜索数小时后,结果应该在CET中。

这是对我有效的解决方案。它也很简单。只需通过减去时区偏移量(以毫秒为单位)来转换时区

25200000=7小时偏移量//420分钟*60秒*1000毫

$group: {
    _id = { 
        year: { $year : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
        month: { $month : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
        day: { $dayOfMonth : [{ $subtract: [ "$timestamp", 25200000 ]}] }
    },
    count = { 
        $sum : 1
    }
};
将时区偏移量与时间戳一起保存:

var now = new Date();
db.data.save( { date: now,
                offset: now.getTimezoneOffset() } );

这当然不是一个理想的解决方案,但在MongoDb的聚合管道中有一个合适的$utcOffset函数之前,这是一个有效的解决方案。

使用例如moment.js来定义CET的当前时区偏移量,但这样可以得到夏季和冬季偏移量

var offsetCETmillisec = moment.tz.zone('Europe/Berlin').offset(moment())* 60 * 1000;

  $group: {
    _id: {
      'year': {'$year': [{ $subtract: [ '$createdAt', offsetCETmillisec ]}] },
      'month': {'$month': [{ $subtract: [ '$createdAt', offsetCETmillisec ]}] },
      'day': {'$dayOfMonth': [{ $subtract: [ '$createdAt', offsetCETmillisec ]}] }
    },
    count: {$sum: 1}
  }
}
您可以提供从3.6开始的日期运算符

将时区替换为您的时区

{
  "$group":{
    "_id":{
      "year":{"$year":{"date":"$tDate","timezone":"America/Chicago"}},
      "month":{"$month":{"date":"$tDate","timezone":"America/Chicago"}},
      "dayOfMonth":{"$dayOfMonth":{"date":"$tDate","timezone":"America/Chicago"}}
    },
    "count":{"$sum":1}
  }
}

使用时区的解决方案是一个很好的解决方案,但在版本3.6中,您也可以使用时区格式化输出,因此,您可以准备好使用结果:

{
"$project":{
    "year_month_day": {"$dateToString": { "format": "%Y-%m-%d", "date": "$tDate", "timezone": "America/Chicago"}}
},
"$group":{
    "_id": "$year_month_day",
    "count":{"$sum":1}
}
}

确保您的“$match”也考虑了时区,否则您将得到错误的结果。

Mongo将日期存储在UTC, 所以这是让他们进入另一个区域的程序

  • 检查mongo是否以UTC格式保存日期,插入一些记录等
  • 使用moment-timezone.js例如矩().tz('Europe/Zagreb').utcOffset()函数获取时区偏移量,以便 指定时区
  • 为$match阶段准备$gte和$lte(如2019年1月1日至2019年1月13日的用户输入):
    • 如果偏移量为正,则减去$match stage中的秒数;如果偏移量为负,则在$match stage中添加()这些秒
  • 然后将日期正常化(因为$match stage将以UTC格式返回日期),如下所示: -如果时区偏移为正,则在$project stage中添加()秒; -如果时区偏移为负,则减去$project stage中的秒数
  • $group放在最后,这一点很重要(因为我们希望对规范化结果进行分组,而不是$match ed)

基本上是这样的:将输入转换为$match(UTC),然后标准化为您的时区。

您的“解决方案”如何将“2013-09-16 23:45:00 UTC”转换为2013-09-17 CET?另一件您没有解释的事情是,如何在mongoDB聚合框架上“包括”您的代码,因为任何转换(或要设置的时区)必须在将日期对象从小时、分钟、秒和毫秒中删除之前完成。“异常:$add仅支持数字或日期类型,而不支持字符串”:(字符串[]date_add_数组={“$t_roundedDateHour”,String.valueOf(3600*1000)};BasicDBObject ProjectionFields=新BasicDBObject(“tDate”,新的BasicDBObject(“$add”,日期添加数组)。追加(“customer”,1)。追加(“eventCount”,1);聚合框架配置为管道,这意味着您可以传入聚合操作数组,它们将按顺序执行,其中一个操作的输出用作输入或下一个操作,依此类推。在shell中,它可能类似于:db.collection.aggregate([{$project:},{$group:}]);我不经常使用java,但这里有一个关于如何使用聚合管道的教程:另外,为了响应您之前的“异常”,您需要使用mongodb的内置日期类型来执行这些操作,而不是字符串。如果整个集合中只有一个字段是字符串,则可能会发生这种异常。是的,我知道关于数据类型的事情(对于Mongo,字符串与数字不同),这就是为什么我提出了另一个问题:由于夏令时的原因,这可能有一半的时间是错误的。大多数使用CET的国家在某个随机日期切换到CEST的夏季时间;当时的差异是+2小时,而不是+1小时。例如,我正在寻找解决此问题的方法,但尚未找到,但请不要使用这个解决方案是原样的,因为夏令时将使这个循环。
{
"$project":{
    "year_month_day": {"$dateToString": { "format": "%Y-%m-%d", "date": "$tDate", "timezone": "America/Chicago"}}
},
"$group":{
    "_id": "$year_month_day",
    "count":{"$sum":1}
}
}