Подтвердить что ты не робот

Как бороться с проблемой часового пояса при хранении дат в utc с использованием mongod?

У меня есть коллекция mongodb, где каждый документ имеет некоторые атрибуты и временную метку utc. Мне нужно вытащить данные из коллекции и использовать структуру агрегации, потому что я использую данные из коллекции, чтобы отобразить некоторые диаграммы на пользовательском интерфейсе. Однако мне нужно выполнить агрегацию в соответствии с часовым поясом пользователя. Предполагая, что я знаю часовой пояс пользователя (переданный в запросе из браузера или каким-либо другим способом), есть ли способ использовать структуру агрегации для агрегирования на основе часового пояса [клиента]?

4b9b3361

Ответ 1

То, о чем вы просите, в настоящее время обсуждается в проблема MongoDB SERVER-6310.

Я нашел это в ссылке из темы обсуждения.

Проблема распространена для любой группировки по дате, включая базы данных SQL и базы данных NoSQL. Фактически, я недавно обратился к этой главе в RavenDB. Существует хорошее описание проблемы и решение RavenDB здесь.

Вопросы MongoDB обсуждают обходное решение, подобное тому, что я описал в комментариях выше. Вы заранее рассчитываете местное время, в котором вы заинтересованы, и группируйте их вместо этого.

Трудно будет охватывать каждый часовой пояс в мире любым из них. Вы должны принять решение о небольшом количестве целевых зон, которые имеют смысл для вашей пользовательской базы, например, подход, созданный для офиса, который я описал в статье RavenDB.

Ответ 2

Помимо SERVER-6310, упомянутого Мэттом Джонсоном, еще одним обходным решением является использование оператора $project для добавления или вычитания из часового пояса UTC для "сдвига времени" в правильную локальную зону. Оказывается, вы можете добавлять или вычитать время в миллисекундах.

Например, если у меня есть поле Date, называемое orderTime. Я бы хотел запросить EDT. Это -4 часа с UTC. Это 4 * 60 * 60 * 1000 миллисекунд.

Итак, я бы написал следующий прогноз, чтобы получить day_ordered по местному времени для всех моих записей:

db.table.aggregate( 
    { $project : { orderTimeLocal : { $subtract : [ "$orderTime", 14400000] } } },
    { $project : { day_ordered : { $dayOfYear : "$orderTimeLocal" } } })

Ответ 3

Каждый предложенный выше подход работает отлично, но поскольку существует новая версия mongodb, начиная с версии 2.6, вы можете использовать $let в структура агрегации, это позволит вам создавать переменные "на лету", тем самым избегая необходимости $project перед группировкой. Теперь вы можете создать переменную с $let, которая будет удерживать локализованное время и использовать ее в операторе $group.

Что-то вроде:

db.test.aggregate([
   {$group: { 
        _id: { 
             $let: { 
                 vars: {  
                     local_time: { $subtract: ["$date", 10800000]} 
                 }, 
                 in: { 
                    $concat: [{$substr: [{$year: "$$local_time"}, 0, 4]}, 
                              "-", 
                              {$substr: [{$month: "$$local_time"}, 0, 2]}, 
                              "-", 
                              {$substr: [{$dayOfMonth: "$$local_time"}, 0, 2]}]
                 }
              }
         }, 
         count: {$sum: 1}
     }
 }])

Обратите внимание, что вы используете $let внутри определения блока/переменной, а значение этого блока/переменной - это возвращаемое значение подвыражения "in", где используются указанные выше vars.

Ответ 4

Я нашел решение в плагин mongoose, чтобы нормализовать часовой пояс сохраненных дат.