6

Я создаю приложение в mongodb и nodejs, которое будет использоваться в Италии. Часовой пояс Италии +02: 00. Это означает, что если кто-нибудь сохранит некоторые данные в 01:00 утра 11 июля, то он будет сохранен как 11:00 вечера 10 июля, так как монго сохраняет дату в UTC. Нам нужно показать дату мудрый счетчик tx. Поэтому я сделал группу по запросу на дату. Но это показывает, что tx в предыдущий день. Что должно быть обходным путем для этого.Агрегирование по местному времени в mongodb

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

Это показывает 2 txs в 10 июля и 1 в 11 июля. Но нам нужно показать 2 txs за 11 июля и 1 tx за 10 июля.

Это было на самом деле 11 июля в Италии, когда

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

прошла, но Монго сохраненной даты как:

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

А что, если кто-то из «Новой Зеландии» захочет просмотреть данные, представленные кем-то в «Италии»? Как вы должны сохранить время? Именно по этой причине используются даты UTC, поскольку они представляют один и тот же момент времени для всех. Преобразуйте в локальное время на своем «клиенте», а также сделайте то же самое с «параметрами запроса», беря локальные даты, а затем преобразуйте их обратно в UTC. Таким образом, запросы и данные согласованы по всему миру. –

+0

@BlakesSeven Но проблема в том, что эта группа показывает эту запись в предыдущую дату. можно ли передавать некоторые параметры, например, в зону дат, делая группу по запросу на манго? –

ответ

3

Работой с часовыми поясами является «клиент» вопрос, так что вам следует быть изменяя время запроса на смещение часового пояса, чтобы разрешить «местный» выбор времени в пользовательском интерфейсе и так далее. То же самое касается отображения пользовательского интерфейса, где даты должны быть представлены в локальное время.

И то же самое относится к вашему принципу arggregation. Просто отрегулируйте смещение по часовой стрелке. Appply дата математике вместо использования операторов агрегирования Дата:

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 эпохи. Просто затем настройте это снова, добавив «смещение часового пояса» как способное для передовых часов, либо отрицательное для сзади, снова преобразованное в действительные миллисекунды из значения времени.

Округление тогда является простым модулем $mod, чтобы получить остаток от «количества миллисекунд в день» и удалите это, чтобы округлить скорректированную дату только до текущего дня.

Результирующие числовые значения здесь легко возвращаются в даты, так как все языковые библиотеки «Дата» объекты принимают миллисекунды (или секунды) от эпохи в качестве аргумента конструктора.

Итак, все это касается изменения ответа на данные из «локали» вашего «клиента», а не для обмена данными о хранении данных. Если вы хотите, чтобы в вашем приложении была истинная локальность, вы применяете модификации для смещения часовых поясов повсюду, как описано выше.

-

На самом деле вы можете просто создать дату в фреймворк агрегации, с немного больше даты математики. Просто добавьте дату эпохи назад к конвертируемой дате:

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

@OmervanKloeten Вздох! Вам нужно подумать об этом сложнее, и я вообще не говорю «скидку на летнее время», но если это будет учитывать диапазон дат ожидаемого результата, тогда вы «справитесь с ним», разбив корректировку по данным локали клиента (т.е. эти даты до простоя DST и эти даты после) для соответствующей корректировки. Хранение содержимого базы данных в GMT «просто имеет смысл», поскольку это стабильная точка, из которой вы можете выполнить все настройки. Это урок здесь. –

0

in mongo version 3.6 часовые пояс был добавлен, mongo doc

выражения для извлечения части даты с временной зоной является

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

{ "_id" : { "day" : 10, "month" : 7, "year" : 2015 }, "count" : 1 } 
{ "_id" : { "day" : 11, "month" : 7, "year" : 2015 }, "count" : 2 } 
> 

timezone

Смежные вопросы