MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Aggregazione Mongodb per giorno e poi per ora

Quello che fondamentalmente vuoi è un doppio raggruppamento, ma non ottieni l'intero oggetto data indietro usando operatori di aggregazione di date , solo le parti rilevanti:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "customerId": "$customerId",
            "day": { "$dayOfYear": "$startTime" },
            "hour": { "$hour": "$startTime" }
        },
        "pings": { "$sum": "$ping" },
        "links": { "$sum": "$link" }
    }},
    { "$group": {
       "_id": {
           "customerId": "$_id.customerId",
           "day": "$_id.day"
       },
       "hours": { 
           "$push": { 
               "hour": "$_id.hour",
               "pings": "$pings",
               "links": "$links"
           }
       }
    }}
])

Il doppio $group ti dà il formato che desideri inserendo i risultati in una matrice al giorno. Singolo documento nell'esempio, ma in pratica ottieni risultati come questo:

{
    "_id" : {
            "customerId" : 123,
            "day" : 365
    },
    "hours" : [
            {
                    "hour" : 10,
                    "pings" : 2,
                    "links" : 3
            }
    ]
}

Se ritieni che i risultati degli operatori di data siano difficili da gestire o desideri un risultato "pass-through" semplificato per gli oggetti data, puoi invece eseguire il cast come timestamp epoch:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "customerId": "$customerId",
            "day": {
               "$subtract": [
                   { "$subtract": [ "$startTime", new Date("1970-01-01") ] },
                   {
                       "$mod": [
                           { "$subtract": [ "$startTime", new Date("1970-01-01") ] },
                           1000*60*60*24   
                       ]
                   }
               ]
            },
            "hour": {
               "$subtract": [
                   { "$subtract": [ "$startTime", new Date("1970-01-01") ] },
                   {
                       "$mod": [
                           { "$subtract": [ "$startTime", new Date("1970-01-01") ] },
                           1000*60*60   
                       ]
                   }
               ]
            }
        },
        "pings": { "$sum": "$ping" },
        "links": { "$sum": "$link" }
    }},
    { "$group": {
       "_id": {
           "customerId": "$_id.customerId",
           "day": "$_id.day"
       },
       "hours": { 
           "$push": { 
               "hour": "$_id.hour",
               "pings": "$pings",
               "links": "$links"
           }
       }
    }}
])

Il trucco è quando $subtract un oggetto data da un altro, di conseguenza, ottieni il valore "epoca". In questo caso utilizziamo la data di inizio "epoca" per ottenere l'intero valore del timestamp e fornire semplicemente la "data matematica" per correggere i tempi agli intervalli richiesti. Quindi il risultato:

{
    "_id" : {
            "customerId" : 123,
            "day" : NumberLong("1419984000000")
    },
    "hours" : [
            {
                    "hour" : NumberLong("1420020000000"),
                    "pings" : 2,
                    "links" : 3
            }
    ]
}

Che potrebbe essere più appetibile per te rispetto a ciò che gli operatori di data forniscono di conseguenza a seconda delle tue esigenze.

Puoi anche aggiungere una piccola scorciatoia per questo con MongoDB 2.6 tramite $let operatore che ti consente di dichiarare "variabili" per operazioni con ambito:

db.event.aggregate([
    { "$group": {
        "_id": {
            "$let": {
                "vars": { 
                   "date": { "$subtract": [ "$startTime", new Date("1970-01-01") ] },
                   "day": 1000*60*60*24,
                   "hour": 1000*60*60
                },
                "in": {
                    "customerId": "$customerId",
                    "day": {
                        "$subtract": [
                            "$$date",
                            { "$mod": [ "$$date", "$$day" ] }
                         ]
                    },
                    "hour": {
                        "$subtract": [
                            "$$date",
                            { "$mod": [ "$$date", "$$hour" ] }
                         ]
                    }
                }
            }
        },
        "pings": { "$sum": "$ping" },
        "links": { "$sum": "$link" }
    }},
    { "$group": {
       "_id": {
           "customerId": "$_id.customerId",
           "day": "$_id.day"
       },
       "hours": { 
           "$push": { 
               "hour": "$_id.hour",
               "pings": "$pings",
               "links": "$links"
           }
       }
    }}
])

Inoltre ho quasi dimenticato di menzionare che i tuoi valori per "ping" e "link" sono in realtà stringhe a meno che non si tratti di un errore di battitura. In caso contrario, assicurati di convertirli prima come numeri.