2014-11-08 13 views
21

Ho una collezione "status" come questo strcture -risultato del Gruppo di 15 minuti intervallo di tempo in MongoDb

{ 
    _id: ObjectId("545a0b63b03dbcd1238b4567"), 
    status: 1004, 
    comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.", 
    created_at: ISODate("2014-11-05T11:34:59.804Z") 
}, 
{ 
    _id: ObjectId("545a0b66b03dbcd1238b4568"), 
    status: 1001, 
    comment: "Sint et eos vero ipsa voluptatem harum. Hic unde voluptatibus et blanditiis quod modi.", 
    created_at: ISODate("2014-11-05T11:35:02.814Z") 
} 
.... 
.... 

ho bisogno di ottenere il risultato raggruppati per 15 minuti di intervallo da quella collezione.

+10

È la loro qualcosa nella risposta a condizione che non è chiaro o non si applica alla tua situazione? Notando che non è ancora accettato. –

+3

Non preoccuparti, ha già preso la risposta, perché preoccuparsi di accettare le risposte. – nurgasemetey

risposta

70

Ci sono un paio di modi per farlo.

Il primo è con Date Aggregation Operators, che consente di sezionare i valori di "data" nei documenti. Specificamente per "raggruppamento" come intento primario:

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "year": { "$year": "$created_at" }, 
      "dayOfYear": { "$dayOfYear": "$created_at" }, 
      "interval": { 
       "$subtract": [ 
        { "$minute": "$created_at" }, 
        { "$mod": [{ "$minute": "$created_at"}, 15] } 
       ] 
      } 
     }}, 
     "count": { "$sum": 1 } 
    }} 
]) 

Il secondo modo è quello di utilizzare un piccolo trucco di quando un oggetto data viene sottratto (o altra operazione diretta matematica) da un altro oggetto data, il risultato è un valore numerico che rappresenta i millisecondi del timestamp in epoca tra i due oggetti. Quindi usando la data dell'epoca si ottiene la rappresentazione dell'epoca millisecondi. Quindi utilizzare la data matematica per l'intervallo:

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "$subtract": [ 
       { "$subtract": [ "$current_date", new Date("1970-01-01") ] }, 
       { "$mod": [ 
        { "$subtract": [ "$current_date", new Date("1970-01-01") ] }, 
        1000 * 60 * 15 
       ]} 
      ] 
     }, 
     "count": { "$sum": 1 } 
    }} 
]) 

Quindi, dipende dal tipo di formato di output desiderato per l'intervallo di raggruppamento. Entrambi rappresentano fondamentalmente la stessa cosa e hanno dati sufficienti per ricostruire come oggetto "data" nel codice.

È possibile inserire qualsiasi altra cosa nella sezione "operatore di raggruppamento" dopo il raggruppamento _id. Sto semplicemente usando l'esempio di base "contare" al posto di qualsiasi affermazione reale da te stesso su ciò che vuoi veramente fare.

+8

peccato che non possa accettare per lui - risposta davvero utile! – Petrov

+2

Non potrei essere più d'accordo @Petrov – aiapatag

+1

Non solo utile ma ben spiegato. –

13

Mi piace l'altra risposta qui, e soprattutto per l'uso di data matematica invece di operatori di data di aggregazione che, sebbene utili, possono anche essere un po 'oscuri.

L'unica cosa che voglio aggiungere qui è che è possibile anche restituire un oggetto Date dal framework di aggregazione con questo approccio in contrasto con il timestamp "numerico" come risultato. E 'solo un po' di matematica in più sugli stessi principi, utilizzando $add:

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "$add": [ 
       { "$subtract": [ 
        { "$subtract": [ "$current_date", new Date(0) ] }, 
        { "$mod": [ 
         { "$subtract": [ "$current_date", new Date(0) ] }, 
         1000 * 60 * 15 
        ]} 
       ] }, 
       new Date(0) 
      ] 
     }, 
     "count": { "$sum": 1 } 
    }} 
]) 

I Date(0) costrutti in JavaScript qui rappresentano la stessa data di "epoca" in una forma più breve, come 0 millisecondi dalla epoca è un'epoca. Ma il punto principale è che quando l'"aggiunta" ad un altro oggetto data BSON viene eseguita con un identificatore numerico, allora l'inverso della condizione descritta è vero e il risultato finale è in realtà ora un Date.

Tutti i driver restituiscono il tipo nativo Date nella propria lingua con questo approccio.

6

Un po 'più bello per mongo db.version() < 3.0

db.collection.aggregate([ 
    {$match: {created_at:{$exists:1}}}, 
    {$group: { 
     _id: {$add:[ 
      {$dayOfYear: "$created_at" }, 
      {$multiply: [{$year: "$created_at"}, 1000]} 
     ]}, 
     count: {$sum: 1 } 
    }}, 
    {$sort:{_id:-1}} 
]) 
2

Un altro modo utile:

db.collection.aggregate([ 
    {$group: { 
    _id: { 
     overallTime: { 
     $dateToString: { format: "%Y-%m-%dT%H", date: "$created_at" } 
     }, 
     interval: { $trunc: { $divide: [{ $minute: "$created_at" }, 15 ]}} 
    }, 
    }}, 
]) 

E più facile per min, ora, giorni intervalli:

var format = "%Y-%m-%dT%H:%M"; // 1 min 
var format = "%Y-%m-%dT%H"; // 1 hour 
var format = "%Y-%m-%d"; // 1 day 

db.collection.aggregate([ 
    {$group: { 
    _id: { $dateToString: { format: format, date: "$created_at" } }, 
    }}, 
]) 
Problemi correlati