MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Mongodb-Aggregation nach Tag und dann nach Stunde

Was Sie im Grunde wollen, ist eine doppelte Gruppierung, aber Sie erhalten nicht das gesamte Datumsobjekt zurück, indem Sie die Datumsaggregationsoperatoren , nur die relevanten Teile:

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"
           }
       }
    }}
])

Die doppelte $group gibt Ihnen das gewünschte Format, indem Sie die Ergebnisse pro Tag in einem Array platzieren. Einzelnes Dokument im Beispiel, aber Sie erhalten im Wesentlichen folgende Ergebnisse:

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

Wenn Sie die Ergebnisse der Datumsoperatoren zu schwierig finden oder ein vereinfachtes "Pass-Through"-Ergebnis für Datumsobjekte wünschen, können Sie stattdessen als Epochen-Zeitstempel umwandeln:

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"
           }
       }
    }}
])

Der Trick dabei ist, wenn Sie $subtract ein Datumsobjekt von einem anderen erhält man als Ergebnis den "Epochen"-Wert zurück. In diesem Fall verwenden wir das Startdatum „Epoche“, um den gesamten Zeitstempelwert zu erhalten, und geben nur die „Datumsmathematik“ an, um die Zeiten auf die erforderlichen Intervalle zu korrigieren. Also das Ergebnis:

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

Was für Sie schmackhafter sein könnte als das, was die Datumsoperatoren je nach Ihren Bedürfnissen als Ergebnis liefern.

Sie können dafür mit MongoDB 2.6 auch eine kleine Abkürzung über $let Operator, mit dem Sie "Variablen" für bereichsbezogene Operationen deklarieren können:

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"
           }
       }
    }}
])

Außerdem hätte ich fast vergessen zu erwähnen, dass Ihre Werte für "ping" und "link" eigentlich Zeichenfolgen sind, es sei denn, das ist ein Tippfehler. Aber wenn nicht, stellen Sie sicher, dass Sie sie zuerst in Zahlen umwandeln.