sql >> データベース >  >> NoSQL >> MongoDB

mongodb集計フレームワークを使用して頻度を計算する

    10秒間隔で物事を取得する場合は、少し計算して、これを集計で実行できます。

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

    つまり、1分間に10秒の間隔に分解され、わずかなmod10の計算で発生します。

    それは合理的であり、骨材を使用しているので最速のランナーになると思います。示されているシーケンスが最初に一致した時間から10秒実行されていることが本当に必要な場合は、mapReduceを使用してプロセスを実行できます:

    最初のマッパー:

    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
        );
    
    }
    

    したがって、これは10秒間隔内で日付を発行し、最初の日付から開始して、範囲外の何かが見つかるたびに間隔を増やします

    今、あなたはレデューサーが必要です:

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

    とてもシンプルです。渡された配列の長さを返すだけです。

    mapReduceはそのように機能するため、複数の値を持たないものはすべてレデューサーに渡されないため、finalizeを使用してこれをクリーンアップします。

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

    次に、それを実行して結果を取得します。マッパーで使用されるグローバル変数を渡す「スコープ」セクションに注意してください。

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

    それぞれのアプローチでわずかに異なる結果が得られる可能性がありますが、それがポイントです。実際に使用したいものによって異なります。

    あなたのコメントを考慮すると、どちらかのステートメントからの出力を「検査」し、プログラムで「ギャップを埋める」ことができます。私は一般的にそのオプションを好みますが、それは私のプログラムではなく、このクエリから取得しようとしているシリーズの大きさもわかりません。

    サーバー側では、「マッパー」にパッチを適用して、次のようなことを行うことができます。

    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:ドキュメントが埋め込まれた効率的なスキーマ設計

    2. MongoDBで友情関係をどのようにモデル化しますか?

    3. 単一の結果を集約して取得することは可能ですか?

    4. $ inc修飾子はmongodbの同時リクエストでどのように機能しますか?