J'essaie de regrouper par horodatage la collection nommée "foo" {_id, TimeStamp}
db.foos.aggregate(
[
{$group : { _id : new Date (Date.UTC({ $year : '$TimeStamp' },{ $month : '$TimeStamp' },{$dayOfMonth : '$TimeStamp'})) }}
])
Attendez-vous à plusieurs dates mais le résultat n'est qu'une date. Les données que j'utilise sont correctes (beaucoup de foo et des dates différentes sauf 1970). Il y a un problème dans l'analyse de la date mais je ne peux pas résoudre pour le moment.
{
"result" : [
{
"_id" : ISODate("1970-01-01T00:00:00.000Z")
}
],
"ok" : 1
}
J'ai essayé celui-ci:
db.foos.aggregate(
[
{$group : { _id : { year : { $year : '$TimeStamp' }, month : { $month : '$TimeStamp' }, day : {$dayOfMonth : '$TimeStamp'} }, count : { $sum : 1 } }},
{$project : { parsedDate : new Date('$_id.year', '$_id.month', '$_id.day') , count : 1, _id : 0} }
])
Résultat :
uncaught exception: aggregate failed: {
"errmsg" : "exception: disallowed field type Date in object expression (at 'parsedDate')",
"code" : 15992,
"ok" : 0
}
Et celui-là:
db.foos.aggregate(
[
{$group : { _id : { year : { $year : '$TimeStamp' }, month : { $month : '$TimeStamp' }, day : {$dayOfMonth : '$TimeStamp'} }, count : { $sum : 1 } }},
{$project : { parsedDate : Date.UTC('$_id.year', '$_id.month', '$_id.day') , count : 1, _id : 0} }
])
Impossible de voir les dates dans le résultat
{
"result" : [
{
"count" : 412
},
{
"count" : 1702
},
{
"count" : 422
}
],
"ok" : 1
}
Cela dépend si vous voulez que la date soit de type ISODate dans la sortie finale. Si c'est le cas, vous pouvez faire l'une des deux choses suivantes:
Extrayez $year
, $month
, $dayOfMonth
de votre horodatage, puis reconstruisez une nouvelle date (vous essayez déjà de le faire, mais vous utilisez une syntaxe qui ne fonctionne pas dans un cadre d'agrégation).
Si l'horodatage d'origine est de type ISODate (), vous pouvez alors effectuer un calcul arithmétique des dates pour soustraire les heures, les minutes, les secondes et les millisecondes de votre horodatage afin d'obtenir une nouvelle date "arrondie" au jour.
Il y a un exemple de 2 ici .
Voici comment vous feriez 1. Je suppose que toutes vos dates sont cette année, mais vous pouvez facilement ajuster les calculs pour vous adapter à votre date la plus ancienne.
project1={$project:{_id:0,
y:{$subtract:[{$year:"$TimeStamp"}, 2013]},
d:{$subtract:[{$dayOfYear:"$TimeStamp"},1]},
TimeStamp:1,
jan1:{$literal:new ISODate("2013-01-01T00:00:00")}
} };
project2={$project:{tsDate:{$add:[
"$jan1",
{$multiply:["$y", 365*24*60*60*1000]},
{$multiply:["$d", 24*60*60*1000]}
] } } };
Échantillon de données:
db.foos.find({},{_id:0,TimeStamp:1})
{ "TimeStamp" : ISODate("2013-11-13T19:15:05.600Z") }
{ "TimeStamp" : ISODate("2014-02-01T10:00:00Z") }
Résultat d'agrégation:
> db.foos.aggregate(project1, project2)
{ "tsDate" : ISODate("2013-11-13T00:00:00Z") }
{ "tsDate" : ISODate("2014-02-01T00:00:00Z") }
db.foos.aggregate(
[
{ $project : { day : {$substr: ["$TimeStamp", 0, 10] }}},
{ $group : { _id : "$day", number : { $sum : 1 }}},
{ $sort : { _id : 1 }}
]
)
Le regroupement par date peut être effectué en deux étapes dans la structure d'agrégation. Une troisième étape supplémentaire est nécessaire pour trier le résultat, si le tri est souhaité:
$project
en combinaison avec $substr
prend les 10 premiers caractères (YYYY: MM: DD) de l'objet ISODate de chaque document (le résultat est une collection de documents avec les champs "_id" et "jour");$group
groupe par jour, en ajoutant (additionnant) le nombre 1 pour chaque document correspondant;$sort
croissant par "_id", qui correspond au jour de la dernière étape d'agrégation. Cette option est facultative si le résultat trié est souhaité.Cette solution ne peut pas tirer parti d'index tels que db.Twitter.ensureIndex( { TimeStamp: 1 } )
, car elle transforme l'objet ISODate en un objet chaîne à la volée. Pour les grandes collections (des millions de documents), cela pourrait constituer un goulot d'étranglement au niveau de la performance et des approches plus sophistiquées devraient être utilisées.
C'est ce que j'utilise dans l'un de mes projets:
collection.aggregate(
// group results by date
{$group : {
_id : { date : "$date" }
// do whatever you want here, like $Push, $sum...
}},
// _id is the date
{$sort : { _id : -1}},
{$orderby: { _id : -1 }})
.toArray()
Où $ date est un objet Date en mongo. Je reçois des résultats indexés par date.