web-dev-qa-db-fra.com

Conversion de date en millisecondes en objet ISODate

J'essaie d'agréger des enregistrements dans une collection MongoDB par heure et j'ai besoin de convertir la date stockée sous forme d'horodatage (millisecondes) en ISODate afin de pouvoir utiliser les opérateurs de date intégrés au cadre global ($ heure, $ mois, etc.).

Les enregistrements sont stockés comme

{ 
"data" : { "UserId" : "abc", "ProjId" : "xyz"}, 
"time" : NumberLong("1395140780706"),
"_id" : ObjectId("532828ac338ed9c33aa8eca7") 
} 

J'essaie d'utiliser une requête globale du type suivant:

db.events.aggregate(
    { 
       $match : { 
         "time" : { $gte : 1395186209804, $lte : 1395192902825 } 
       } 
    }, 
    { 
       $project : {
         _id : "$_id", 
         dt : {$concat : (Date("$time")).toString()} // need to project as ISODate
       } 
    },
    // process records further in $project or $group clause
)

qui produit des résultats de la forme:

{
    "result" : [
        { 
            "_id" : ObjectId("5328da21fd207d9c3567d3ec"), 
            "dt" : "Fri Mar 21 2014 17:35:46 GMT-0400 (EDT)" 
        }, 
        { 
            "_id" : ObjectId("5328da21fd207d9c3567d3ed"), 
            "dt" : "Fri Mar 21 2014 17:35:46 GMT-0400 (EDT)" 
        }, 
            ... 
} 

Je souhaite extraire l'heure, le jour, le mois et l'année de la date, mais comme l'heure est projetée en tant que chaîne, je ne peux pas utiliser les opérateurs de date intégrés au framework global ($ hour, etc.). 

Comment puis-je convertir le temps en millisecondes en date ISO comme suit:

db.events.aggregate(
    {
        $match : { 
            "time" : { $gte : 1395186209804, $lte : 1395192902825 } 
        }
    },
    {
        $project : {
            _id : "$_id",
            dt : <ISO date from "$time">
        }
    },
    { 
        $project : {
            _id : "$_id",
            date : { 
                hour : {$hour : "$dt"} 
            }
        }
    }
)
20
Sid Thakur

Je suppose qu'il n'y a aucun moyen de le faire. Parce que la structure d'agrégation est écrite en code natif. ne pas utiliser le moteur V8. Ainsi, tout le JavaScript ne fonctionnera pas dans le cadre (et c’est aussi pourquoi le cadre d’agrégation est beaucoup plus rapide).
Mapper/Réduire est une façon de résoudre ce problème, mais le cadre d’agrégation a nettement mieux performé.

À propos des performances de la carte/réduction, lisez ce fil de discussion .

Une autre solution consiste à obtenir un résultat "brut" du framework d'agrégation, à le placer dans un tableau JSON. Ensuite, effectuez la conversion en exécutant JavaScript. Un peu comme:

var results = db.events.aggregate(...);
reasult.forEach(function(data) {
    data.date = new Date(data.dateInMillionSeconds);
    // date is now stored in the "date" property
}
7
yaoxing

En fait, c’est possible, l’astuce consiste à ajouter votre temps en millisecondes à un objet Date () à zéro millisecondes en utilisant une syntaxe semblable à celle-ci:

dt : {$add: [new Date(0), "$time"]}

J'ai modifié votre agrégation d'en haut pour produire le résultat:

db.events.aggregate(
    {
        $project : {
            _id : "$_id",
            dt : {$add: [new Date(0), "$time"]}
        }
    },
    { 
        $project : {
            _id : "$_id",
            date : { 
                hour : {$hour : "$dt"} 
            }
        }
    }
);

Le résultat est (avec une entrée de vos données d'échantillon):

{
  "result": [
    {
      "_id": ObjectId("532828ac338ed9c33aa8eca7"),
      "date": {
        "hour": 11
      }
    }
  ],
  "ok": 1
}
31
Astral

Pour renvoyer une date BSON valide, il vous suffit d'une petite date "mathématique" à l'aide de l'opérateur $add . Vous devez ajouter new Date(0) à l'horodatage. La new Date(0) représente le nombre de millisecondes écoulées depuis l’époque Unix (1er janvier 1970) et est un raccourci pour new Date("1970-01-01").

db.events.aggregate([
    { "$match": { "time": { "$gte" : 1395136209804, "$lte" : 1395192902825 } } },
    { "$project": { 
        "hour": { "$hour": { "$add": [ new Date(0), "$time" ] } }, 
        "day": { "$dayOfMonth":  { "$add": [ new Date(0), "$time" ] } },
        "month": { "$month": { "$add": [ new Date(0), "$time" ] } },
        "year": { "$year":  { "$add": [ new Date(0), "$time" ] } } 
    }} 
])

Quels rendements:

{
    "_id" : ObjectId("532828ac338ed9c33aa8eca7"),
    "hour" : 11,
    "day" : 18,
    "month" : 3,
    "year" : 2014
}
2
styvane

utiliser ceci si la fonction {$add: [new Date(0), "$time"]} renvoie string type et non un ISO date type

J'utilise toute cette option mais j'échoue quand même, car ma nouvelle date de $project renvoie un string type tel que '2000-11-2:xxxxxxx' pas date type comme ISO('2000-11-2:xxxxxxx') pour tous ceux qui ont le même problème que moi.

db.events.aggregate(
    {
        $project : {
            _id : "$_id",
            dt : {$add: [new Date(0), "$time"]}
        }
    },
    { 
        $project : {
            _id : "$_id",
            "year": { $substr: [ "$dt", 0, 4 ] },
            "month": { $substr: [ "$dt", 5, 2] },
            "day": { $substr: [ "$dt", 8, 2 ] }
        }
    }
);

le résultat sera

 { _id: '59f940eaea87453b30f42cf5',
    year: '2017',
    month: '07',
    day: '04' 
},

vous pouvez obtenir des heures ou des minutes si vous le souhaitez en fonction de la string que vous souhaitez subset, vous pouvez alors groupdéfinir à nouveau selon la même date, mois ou année

0
KEKUATAN