2017-08-29 3 views
1

j'ai les données de séries chronologiques suivantes stockées dans MongoDB

{ 
    "_id" : ObjectId("59a46062e1aeb958a712490e"), 
    "channelName" : "ABC", 
    "rtData" : [ 
    { 
     "ts" : ISODate("2017-08-28T18:26:42.837Z"), 
     "data" : [ 676.297664, 676.297664 ] 
    }, 
    { 
     "ts" : ISODate("2017-08-28T18:27:42.837Z"), 
     "data" : [ 724.297664, 676.297664 ] 
    }, 
    { 
     "ts" : ISODate("2017-08-28T18:29:42.837Z"), 
     "data" : [ 878.297, 676.297 ] 
    } 
    ] 
} 

Je veux regrouper les données en fonction du champ ts sur l'heure et obtenir le premier élément de rtData pour que heure. Voici ce que j'ai essayé

db.channels.aggregate([ {$match: {"channelName": "ABC"} }, { $unwind : "$rtData" }, { $group : {_id: { $hour: "$rtData.ts" }, ucast: { $sum: $rtData.data[0]} } 

Mais le code ci-dessus me donne la sortie suivante

{ "_id" : 28, "ucast" : 0 } 

Ce que je veux vraiment est

{ "_id" : 28, "ucast" : 676.297664 } 

Répondre

0

Vous ne Notate pas obtenir un premier élément d'un tableau dans un pipeline d'agrégation comme ça. Vous voulez $arrayElemAt qui retourne la valeur de tableau par index:

db.channels.aggregate([ 
    { $match: {"channelName": "ABC"} }, 
    { $unwind : "$rtData" }, 
    { $group : { 
    _id: { $hour: "$rtData.ts" }, 
    ucast: { $sum: { $arrayElemAt: [ "$rtData.data", 0 ] } } 
    }} 
]) 

Si votre MongoDB ne supporte pas $arrayElemAt (avant 3.2), vous pouvez utiliser à la place $first dans un $group supplémentaire juste la clé du document, fait avant « accumuler » pour le choix de groupement clé:

db.channels.aggregate([ 
    { $match: {"channelName": "ABC"} }, 
    { $unwind : "$rtData" }, 
    { $group: { 
    _id: { _id: "$_id", ts: "$rtData.ts" }, 
    data: { $first: "$rtData.data" } 
    }}, 
    { $group : { 
    _id: { $hour: "$_id.ts" }, 
    ucast: { $sum: "$data" } 
    }} 
]) 

Dans les versions modernes, vous pouvez « double barillet » le $sum à la fois ajouter des éléments du tableau ainsi que d'agir comme un accumulateur si vous voulez « somme » tous eleme nts du tableau:

db.channels.aggregate([ 
    { $match: {"channelName": "ABC"} }, 
    { $unwind : "$rtData" }, 
    { $group : { 
    _id: { $hour: "$rtData.ts" }, 
    ucast: { $sum: { $sum: "$rtData.data" } } 
    }} 
]) 

Et avec les versions plus anciennes (avant 3.2), vous « double » $unwind pour chaque chemin de tableau au lieu:

db.channels.aggregate([ 
    { $match: {"channelName": "ABC"} }, 
    { $unwind : "$rtData" }, 
    { $unwind : "$rtData.data" }, 
    { $group : { 
    _id: { $hour: "$rtData.ts" }, 
    ucast: { $sum: "$rtData.data" } 
    }} 
]) 
+0

Merci cela fonctionne. – Neeraj

+0

@Neeraj Bienvenue sur StackOverflow. Ne laissez pas un commentaire en disant merci, mais plutôt indiquer la bonne réponse en [Acceptant la réponse] (https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) qui est une indication claire. –

0

vous devez utiliser $ premier opérateur pour qu'au lieu de $ somme

db.channels.aggregate([ {$match: {"channelName": "ABC"} }, { $unwind : "$rtData" }, { $group : {_id: { $hour: "$rtData.ts" }, ucast: { $first: $rtData.data} } 

qui vous donnera la sortie comme { "_id": 28 "UCAST": [676,297664, 676,297664]}

si vous voulez la sortie comme {"_id": 28, "ucast": 676.297664} dans le prochain projet $ ou $ addFields utiliser la scène $ arrayElemAt