MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Agrégation Mongodb par jour puis heure

Ce que vous voulez essentiellement, c'est un double regroupement, mais vous ne récupérez pas l'intégralité de l'objet date en utilisant le opérateurs d'agrégation de dates , juste les parties pertinentes :

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

Le double $group vous donne le format que vous souhaitez en plaçant les résultats dans un tableau par jour. Document unique dans l'exemple, mais vous obtenez essentiellement des résultats comme celui-ci :

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

Si vous trouvez que les résultats des opérateurs de date sont difficiles à gérer ou si vous souhaitez un résultat de "passage" simplifié pour les objets de date, vous pouvez plutôt les convertir en horodatages d'époque :

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

Le truc là-dedans, c'est quand vous $subtract un objet de date d'un autre, vous récupérez la valeur "epoch" en conséquence. Dans ce cas, nous utilisons la date de début "epoch" pour obtenir la valeur d'horodatage complète et fournissons simplement les "calculs de date" pour corriger les heures aux intervalles requis. Donc le résultat :

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

Ce qui pourrait être plus acceptable pour vous que ce que les opérateurs de date fournissent en conséquence en fonction de vos besoins.

Vous pouvez également ajouter un petit raccourci pour cela avec MongoDB 2.6 via le $let opérateur qui vous permet de déclarer des "variables" pour les opérations étendues :

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

De plus, j'ai presque oublié de mentionner que vos valeurs pour "ping" et "link" sont en fait des chaînes, sauf si c'est une faute de frappe. Mais si ce n'est pas le cas, assurez-vous de les convertir d'abord en nombres.