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