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

mongodb集計クエリが$sumの使用時に適切な合計を返していません

    現在のスキーマにはmarksがあります 文字列としてのフィールドデータ型。合計を計算するには、集計フレームワークに整数データ型が必要です。一方、MapReduce を使用できます。 parseInt()などのネイティブJavaScriptメソッドを使用できるため、合計を計算します マップ関数のオブジェクトプロパティ。したがって、全体として2つの選択肢があります。

    オプション1:スキーマの更新(データ型の変更)

    1つ目は、スキーマを変更するか、文字列表現ではなく実際の数値を持つ別のフィールドをドキュメントに追加することです。コレクションドキュメントのサイズが比較的小さい場合は、mongodbのカーソルを組み合わせて使用​​できます find() forEach() およびupdate() マークスキーマを変更する方法:

    db.student.find({ "marks": { "$type": 2 } }).snapshot().forEach(function(doc) {
        db.student.update(
            { "_id": doc._id, "marks": { "$type": 2 } }, 
            { "$set": { "marks": parseInt(doc.marks) } }
        );
    });
    

    コレクションサイズが比較的大きい場合、dbのパフォーマンスは遅くなるため、mongoの一括更新 このために:

    MongoDBバージョン>=2.6および<3.2:

    var bulk = db.student.initializeUnorderedBulkOp(),
        counter = 0;
    
    db.student.find({"marks": {"$exists": true, "$type": 2 }}).forEach(function (doc) {    
        bulk.find({ "_id": doc._id }).updateOne({ 
            "$set": { "marks": parseInt(doc.marks) } 
        });
    
        counter++;
        if (counter % 1000 === 0) {
            // Execute per 1000 operations 
            bulk.execute(); 
    
            // re-initialize every 1000 update statements
            bulk = db.student.initializeUnorderedBulkOp();
        }
    })
    
    // Clean up remaining operations in queue
    if (counter % 1000 !== 0) bulk.execute(); 
    

    MongoDBバージョン3.2以降:

    var ops = [],
        cursor = db.student.find({"marks": {"$exists": true, "$type": 2 }});
    
    cursor.forEach(function (doc) {     
        ops.push({ 
            "updateOne": { 
                "filter": { "_id": doc._id } ,              
                "update": { "$set": { "marks": parseInt(doc.marks) } } 
            }         
        });
    
        if (ops.length === 1000) {
            db.student.bulkWrite(ops);
            ops = [];
        }     
    });
    
    if (ops.length > 0) db.student.bulkWrite(ops);
    

    オプション2:MapReduceを実行する

    2番目のアプローチは、MapReduce を使用してクエリを書き直すことです。 ここで、JavaScript関数parseInt()を使用できます 。

    MapReduce 操作では、各入力ドキュメントを処理するマップ関数を定義します。この関数は、変換されたmarksをマップします subjectへの文字列値 ドキュメントごとに、subjectを発行します 変換されたmarks ペア。ここで、JavaScriptネイティブ関数parseInt() 適用することができます。注:関数では、this map-reduce操作が処理しているドキュメントを参照します:

    var mapper = function () {
        var x = parseInt(this.marks);
        emit(this.subject, x);
    };
    

    次に、2つの引数keySubjectを使用して対応するreduce関数を定義します。 およびvaluesMarksvaluesMarks 要素が整数のmarksである配列です。 map関数によって発行され、keySubjectによってグループ化された値 。この関数はvaluesMarksを減らします 要素の合計に配列します。

    var reducer = function(keySubject, valuesMarks) {
        return Array.sum(valuesMarks);
    };
    
    db.student.mapReduce(
        mapper,
        reducer,
        {
            out : "example_results",
            query: { subject : "maths" }       
        }
     );
    

    コレクションを使用すると、上記でMapReduce集計結果が新しいコレクションdb.example_resultsに配置されます。 。したがって、db.example_results.find() 出力されます:

    /* 0 */
    {
        "_id" : "maths",
        "value" : 163
    }
    


    1. マルチレベルのオブジェクト値に基づく条件でネストされた配列をフィルタリングし、それらを更新します-MongoDB集計+更新

    2. MongoDB:BSONからJSON

    3. MongoDBはサブドキュメントを取得します

    4. expressjs、mongodbサイトの画像を保存するための最良の方法はどれですか?