sql >> Database >  >> NoSQL >> MongoDB

bereken de frequentie met behulp van het mongodb-aggregaatraamwerk

Als het erom gaat dingen binnen een interval van 10 seconden te krijgen, kun je een beetje rekenen en dit door het aggregaat halen:

db.collection.aggregate([
    { "$group": {
        "_id": {
             "year": { "$year": "$created_at" },
             "month":{ "$month": "$created_at" },
             "day": { "$dayOfMonth": "$created_at" },
             "hour": { "$hour": "$created_at" },
             "minute": { "$minute": "$created_at" },
             "second": { "$subtract": [
                 { "$second": "$created_at" },
                 { "$mod": [
                     { "$second": "$created_at" },
                     10
                 ]}
             ]}
        },
        "count": { "$sum" : 1 }
    }}
])

Dus dat verdeelt de dingen in intervallen van 10 seconden in een minuut, waar ze voorkomen met een beetje mod 10 wiskunde.

Ik denk dat dat redelijk is en de snelste hardloper zou zijn omdat het aggregaat gebruikt. Als je je reeks echt nodig hebt, zoals wordt weergegeven als een lopende 10 seconden vanaf een aanvankelijk overeenkomende tijd, dan kun je het proces doen met mapReduce:

Eerst een mapper:

var mapper = function () {

    if ( this.created_at.getTime() > ( last_date + 10000 ) ) {
        if ( last_date == 0 ) {
            last_date = this.created_at.getTime();
        } else {
            last_date += 10000;
        }
    }

    emit(
        {
            start: new Date( last_date ),
            end: new Date( last_date + 10000 )
        },
        this.created_at
    );

}

Dit gaat dus datums uitzenden binnen een interval van 10 seconden, te beginnen met de eerste datum en vervolgens het interval te verhogen telkens wanneer er iets buiten het bereik wordt gevonden

Nu heb je een verloopstuk nodig:

var reducer = function (key, values) {
    return values.length;
};

Erg makkelijk. Retourneer gewoon de lengte van de ingevoerde array.

Omdat mapReduce werkt zoals het werkt, wordt alles dat niet meer dan één waarde had niet doorgegeven aan het verloopstuk, dus ruim dit op met finalize:

var finalize = function (key, value) {
    if ( typeof(value) == "object" ) {
        value = 1;
    }
    return value;
};

Voer het dan gewoon uit om de resultaten te krijgen. Let op de sectie "scope" die een globale variabele doorgeeft die in de mapper moet worden gebruikt:

db.collection.mapReduce(
    mapper,
    reducer,
    { 
        "out": { "inline": 1 }, 
        "scope": { "last_date": 0 }, 
        "finalize": finalize 
    }
)

Elke benadering zal waarschijnlijk iets andere resultaten opleveren, maar dat is het punt. Het hangt ervan af welke je echt wilt gebruiken.

Gezien uw opmerking zou u ofwel de uitvoer van beide verklaringen kunnen "inspecteren" en als het ware programmatisch "de gaten opvullen". Ik geef over het algemeen de voorkeur aan die optie, maar het is niet mijn programma en ik weet niet hoe groot een reeks is die u probeert op te halen uit deze zoekopdracht.

Aan de serverkant kun je de "mapper" patchen om zoiets als dit te doen:

var mapper = function () {

    if ( this.created_at.getTime() > ( last_date + 10000 ) ) {

        if ( last_date == 0 ) {
            last_date = this.created_at.getTime();
        } else {
            // Patching for empty blocks
            var times = Math.floor( 
                 ( this.created_at.getTime() - last_date ) / 10000
            );

            if ( times > 1 ) {
                for ( var i=1; i < times; i++ ) {
                    last_date += 10000;
                    emit(
                        {
                            start: new Date( last_date ),
                            end: new Date( last_date + 10000 )
                        },
                        0
                    );
                }
            }
            // End patch
            last_date += 10000;
        }
    }

    emit(
        {
            start: new Date( last_date ),
            end: new Date( last_date + 10000 )
        },
        this.created_at
    );

}



  1. MongoDB-indexering voor een Parse Server-toepassing

  2. Proberen te vullen in mangoest alleen als ref niet null is - werkt niet

  3. Spring Data Redis:Redis Pipeline retourneert altijd null

  4. MongoDB $dayOfYear