Comment traiter le problème de fuseau horaire lors du stockage des dates en utc en utilisant mongod?

J'ai une collection mongodb où chaque document a des attributs et un horodatage utc. J'ai besoin de retirer les données de la collection et d'utiliser le framework d'agrégation car j'utilise les données de la collection pour afficher des graphiques sur l'interface utilisateur. Cependant, je dois faire l'agrégation selon le fuseau horaire de l'utilisateur. En supposant que je connaisse le fuseau horaire de l'utilisateur(passé dans la requête du navigateur ou d'une autre manière), est - il possible d'utiliser le framework d'agrégation pour agréger basé sur le fuseau horaire [du client]?

28
demandé sur Hrishi 2013-08-17 13:59:09

4 réponses

Ce que vous demandez est actuellement discuté dansMongoDB issue SERVER-6310 .

J'ai trouvé cela dans un lien de un fil de discussion .

Le problème est commun pour tout regroupement par date, y compris les bases de données SQL et les bases de données NoSQL. En fait, j'ai récemment abordé cette question à RavenDB. Il y a une bonne description du problème et une solution RavenDB ici .

Les problèmes MongoDB discutent d'une solution de contournement, qui est similaire à ce que je décrit dans les commentaires ci-dessus. Vous précalculez les heures locales qui vous intéressent et regroupez-les par celles-ci.

Il sera difficile de couvrir tous les fuseaux horaires du monde avec l'une ou l'autre approche. Vous devriez décider d'une petite poignée de zones cibles qui ont du sens pour votre base d'utilisateurs, comme l'approche par bureau que j'ai décrite dans L'article RavenDB.

Mise à jour: ce problème a été résolu dans MongoDB en juillet 2017 (version 3.5.11)., La solution est décrite dans la première lien ci-dessus, mais en bref, ils ont introduit un nouveau format d'objet pour les dates dans les expressions d'agrégation: { date: <dateExpression>, timezone: <tzExpression> } qui vous permet de spécifier un fuseau horaire à utiliser lors de l'agrégation. Voir ici pour un autre exemple dans les documents Mongo.

9
répondu Matt Johnson 2018-03-05 16:48:45

Mis à part le serveur-6310 mentionné par Matt Johnson, une autre solution consiste à utiliser l'opérateur $project pour ajouter ou soustraire du fuseau horaire UTC pour "décaler l'heure" dans la zone locale correcte. Vous pouvez ajouter ou soustraire le temps en millisecondes.

Par exemple, en supposant que j'ai un champ de Date appelé orderTime. Je voudrais demander pour EDT. C'est -4 heures D'UTC. C'est 4 * 60 * 60 * 1000 millisecondes.

Donc j'écrirais alors la projection suivante pour obtenir day_ordered dans heure locale pour tous mes enregistrements:

db.table.aggregate( 
    { $project : { orderTimeLocal : { $subtract : [ "$orderTime", 14400000] } } },
    { $project : { day_ordered : { $dayOfYear : "$orderTimeLocal" } } })
36
répondu Astral 2017-03-08 11:13:14

Chaque approche suggérée ci-dessus fonctionne parfaitement, mais comme il existe une nouvelle version de mongodb, à partir de 2.6, vous pouvez utiliser $let dans le cadre d'agrégation, cela vous permettra de créer des variables à la volée, évitant ainsi le besoin de $project avant le regroupement. Maintenant, vous pouvez créer une variable avec $let qui contiendra l'heure localisée, et l'utiliser dans l'opérateur $group.

Quelque Chose comme:

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

Notez que vous utilisez $let dans la définition d'un bloc / variable, et la valeur de ce bloc / variable est la valeur renvoyée de la sous-expression "in", où les variables définies ci-dessus sont utilisées.

16
répondu Sebastian 2015-11-06 08:50:18

J'ai trouvé une solution dans le plugin mongoose pour normaliser le fuseau horaire des dates stockées.

1
répondu Emir Mamashov 2017-09-12 02:18:02