sql >> Databáze >  >> NoSQL >> MongoDB

Mongo agregace v časových intervalech

Existuje několik způsobů, jak toho dosáhnout v závislosti na tom, který výstupní formát nejlépe vyhovuje vašim potřebám. Hlavní poznámka je, že s "rámcem agregace" ve skutečnosti nemůžete vrátit něco "obsazeno" jako datum, ale můžete získat hodnoty, které lze snadno rekonstruovat do Date objekt při zpracování výsledků ve vašem rozhraní API.

Prvním přístupem je použití "Date Aggregation Operators" dostupné pro agregační rámec:

db.collection.aggregate([
    { "$match": {
        "time": { "$gte": startDate, "$lt": endDate }
    }},
    { "$group": {
        "_id": {
            "year": { "$year": "$time" },
            "dayOfYear": { "$dayOfYear": "$time" },
            "hour": { "$hour": "$time" },
            "minute": {
                "$subtract": [
                    { "$minute": "$time" },
                    { "$mod": [ { "$minute": "$time" }, 10 ] }
                ]
            }
        },
        "count": { "$sum": 1 }
    }}
])

Což vrací složený klíč pro _id obsahující všechny hodnoty, které chcete pro "datum". Alternativně, pokud vždy jen do „hodiny“, pak stačí použít část „minuta“ a zjistit skutečné datum na základě startDate z vašeho výběru rozsahu.

Nebo můžete jednoduše použít prostý "Date math" a získat milisekundy od "epochy", které lze opět přenést přímo do data constructor.

db.collection.aggregate([
    { "$match": {
        "time": { "$gte": startDate, "$lt": endDate }
    }},
    { "$group": {
        "_id": {
            "$subtract": [
               { "$subtract": [ "$time", new Date(0) ] },
               { "$mod": [
                   { "$subtract": [ "$time", new Date(0) ] },
                   1000 * 60 * 10
               ]}
            ]
        },
        "count": { "$sum": 1 }
    }}
])

Ve všech případech to, co neděláte chci udělat, je použít $project před skutečným použitím $group . Jako "projektová fáze", $project musí „cyklovat“ všemi vybranými dokumenty a „transformovat“ obsah.

To zabere čas a přidá k celkovému počtu provedení dotazu. Můžete se jednoduše přihlásit do $group přímo, jak bylo ukázáno.

Nebo pokud jste opravdu "čistí" ohledně Date objekt se vrací bez následného zpracování, pak můžete vždy použít "mapReduce" , protože funkce JavaScriptu ve skutečnosti umožňují přetypování jako datum, ale pomaleji než agregační rámec a samozřejmě bez odezvy kurzoru:

db.collection.mapReduce(
   function() {
       var date = new Date(
           this.time.valueOf() 
           - ( this.time.valueOf() % ( 1000 * 60 * 10 ) )
       );
       emit(date,1);
   },
   function(key,values) {
       return Array.sum(values);
   },
   { "out": { "inline": 1 } }
)

Nejlepším řešením je však použití agregace, protože transformace odpovědi je docela snadná:

db.collection.aggregate([
    { "$match": {
        "time": { "$gte": startDate, "$lt": endDate }
    }},
    { "$group": {
        "_id": {
            "year": { "$year": "$time" },
            "dayOfYear": { "$dayOfYear": "$time" },
            "hour": { "$hour": "$time" },
            "minute": {
                "$subtract": [
                    { "$minute": "$time" },
                    { "$mod": [ { "$minute": "$time" }, 10 ] }
                ]
            }
        },
        "count": { "$sum": 1 }
    }}
]).forEach(function(doc) {
    doc._id = new Date(doc._id);
    printjson(doc);
})

A pak máte výstup seskupení intervalů se skutečným Date objektů.



  1. MongoDB:aktualizujte pouze konkrétní pole

  2. mongodb - provést dávkový dotaz

  3. Jak zadat preferenci čtení v dotazech Meteor mongo

  4. sdílení db připojení v celé aplikaci v mongoose