sql >> Database >  >> NoSQL >> MongoDB

Mongodb-aggregatie per dag dan uur

Wat je eigenlijk wilt is een dubbele groepering, maar je krijgt niet het hele date-object terug met de operators voor datumaggregatie , alleen de relevante onderdelen:

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

De dubbele $group geeft u het gewenste formaat door de resultaten per dag in een array te plaatsen. Eén document in het voorbeeld, maar u krijgt in principe de volgende resultaten:

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

Als u de resultaten van de datumoperatoren te moeilijk vindt om mee om te gaan of als u een vereenvoudigd "pass-through"-resultaat voor datumobjecten wilt, dan kunt u in plaats daarvan als epoch-tijdstempels casten:

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

De truc is wanneer je $subtract het ene datumobject van het andere krijg je daardoor de "epoch"-waarde terug. In dit geval gebruiken we de "epoch" startdatum om de hele tijdstempelwaarde te krijgen en geven we gewoon de "date math" om de tijden te corrigeren naar de vereiste intervallen. Dus het resultaat:

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

Wat voor u misschien smakelijker is dan wat de datumoperators bieden, afhankelijk van uw behoeften.

Je kunt hier ook een korte afkorting voor toevoegen met MongoDB 2.6 via de $let operator waarmee u "variabelen" kunt declareren voor bewerkingen met een bereik:

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

Ook vergat ik bijna te vermelden dat uw waarden voor "ping" en "link" eigenlijk strings zijn, tenzij dat een typfout is. Maar als dat niet het geval is, zorg er dan voor dat je ze eerst als getallen converteert.




  1. Tijdsprecisieprobleem bij vergelijking in mongodb-stuurprogramma in Go en mogelijk in een andere taal en andere database

  2. Redis:retourneert alle waarden die zijn opgeslagen in een database

  3. g++ kan libmongcxx(r3.0.2) niet statisch linken, maar dynamische link werkt

  4. Hoe een node.js met redis op kubernetes te implementeren?