Jak poradzić sobie z problemem strefy czasowej podczas przechowywania dat w utc za pomocą mongod?

Mam kolekcję mongodb, gdzie każdy dokument ma pewne atrybuty i znacznik czasu utc. Muszę wyciągnąć dane z kolekcji i użyć frameworka agregacji, ponieważ używam danych z kolekcji do wyświetlania niektórych Wykresów w interfejsie użytkownika. Jednak muszę wykonać agregację zgodnie z strefą czasową użytkownika. Zakładając, że znam strefę czasową użytkownika (przekazaną w żądaniu z przeglądarki lub w inny sposób), czy jest jakiś sposób na użycie frameworka agregacji do agregowania opartego w strefie czasowej [klienta]?

Author: Hrishi, 2013-08-17

4 answers

To, o co prosisz, jest obecnie omawiane w MongoDB issue SERVER-6310 .

Znalazłem to w linku z wątku Dyskusyjnego .

Problem jest powszechny dla dowolnego grupowania według daty, w tym baz danych SQL i baz danych NoSQL. W rzeczywistości, niedawno zwróciłem się do tej głowy w RavenDB. Jest tu dobry opis problemu i rozwiązanie RavenDB .

Problemy MongoDB omawiają obejście, które jest podobne do tego, co ja opisane w komentarzach powyżej. Wstępnie obliczasz godziny lokalne, które Cię interesują, i grupujesz je zamiast nich.

Trudno będzie pokryć każdą strefę czasową na świecie z którymkolwiek podejściem. Powinieneś zdecydować się na niewielką garść stref docelowych, które mają sens dla twojej bazy użytkowników, takich jak podejście per-office, które opisałem w artykule RavenDB.

Aktualizacja: ten problem został rozwiązany w MongoDB w lipcu 2017 (Wersja 3.5.11). rozwiązanie opisane jest w pierwszym link powyżej, ale w skrócie wprowadzili nowy format obiektów dla dat w wyrażeniach agregujących: { date: <dateExpression>, timezone: <tzExpression> }, który pozwala określić strefę czasową, która ma być używana podczas agregowania. Zobacz tutaj dla innego przykładu w Mongo docs.

 9
Author: Matt Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-05 16:48:45

Poza serwerem-6310 wspomnianym przez Matta Johnsona, innym obejściem jest użycie operatora $project do dodawania lub odejmowania ze strefy czasowej UTC w celu "przesunięcia czasu" do właściwej strefy lokalnej. Okazuje się, że można dodać lub odjąć czas w milisekundach.

Na przykład, zakładając, że mam pole daty o nazwie orderTime. Chciałbym zapytać o EDT. Czyli -4 godziny od UTC. To 4 * 60 * 60 * 1000 milisekundy.

Więc napiszę następującą projekcję, aby uzyskać day_ordered w czas lokalny dla wszystkich moich rekordów:

db.table.aggregate( 
    { $project : { orderTimeLocal : { $subtract : [ "$orderTime", 14400000] } } },
    { $project : { day_ordered : { $dayOfYear : "$orderTimeLocal" } } })
 36
Author: Astral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-08 11:13:14

Każde podejście zaproponowane powyżej działa idealnie, ale ponieważ istnieje nowa wersja mongodb, od 2.6 możesz użyć $let w ramach agregacji pozwala to na tworzenie zmiennych w locie, unikając w ten sposób konieczności $project przed grupowaniem. Teraz możesz utworzyć zmienną z $let, która będzie przechowywać czas lokalny i używać go w operatorze $group.

Coś w stylu:

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

Zauważ, że używasz $let wewnątrz definicji bloku / zmiennej, a wartość tego bloku / zmiennej jest zwracaną wartością podwyrażenia "in", gdzie używane są wyżej zdefiniowane zmienne.

 16
Author: Sebastian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-06 08:50:18

Znalazłem rozwiązanie w mongoose plugin do normalizacji przechowywanej strefy czasowej dat.

 1
Author: Emir Mamashov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-12 02:18:02