MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

kueri agregat mongodb tidak mengembalikan jumlah yang tepat saat menggunakan $sum

Skema Anda saat ini memiliki marks tipe data bidang sebagai string dan Anda memerlukan tipe data integer untuk kerangka kerja agregasi Anda untuk menghitung jumlahnya. Di sisi lain, Anda dapat menggunakan MapReduce untuk menghitung jumlah karena memungkinkan penggunaan metode JavaScript asli seperti parseInt() pada properti objek Anda dalam fungsi petanya. Jadi secara keseluruhan Anda memiliki dua pilihan.

Opsi 1:Skema Pembaruan (Ubah Jenis Data)

Yang pertama adalah mengubah skema atau menambahkan bidang lain di dokumen Anda yang memiliki nilai numerik aktual bukan representasi string. Jika ukuran dokumen koleksi Anda relatif kecil, Anda dapat menggunakan kombinasi kursor mongodb find() , forEach() dan update() metode untuk mengubah skema tanda Anda:

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

Untuk ukuran koleksi yang relatif besar, kinerja db Anda akan lambat dan disarankan untuk menggunakan pembaruan massal mongo untuk ini:

Versi MongoDB>=2.6 dan <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 versi 3.2 dan yang lebih baru:

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

Opsi 2:Jalankan MapReduce

Pendekatan kedua adalah menulis ulang kueri Anda dengan MapReduce di mana Anda dapat menggunakan fungsi JavaScript parseInt() .

Dalam MapReduce Anda operasi, tentukan fungsi peta yang memproses setiap dokumen input. Fungsi ini memetakan marks . yang dikonversi nilai string ke subject untuk setiap dokumen, dan memancarkan subject dan mengonversi marks pasangan. Di sinilah fungsi asli JavaScript parseInt() dapat diaplikasikan. Catatan:dalam fungsi, this mengacu pada dokumen yang sedang diproses oleh operasi pengurangan peta:

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

Selanjutnya, tentukan fungsi pengurangan yang sesuai dengan dua argumen keySubject dan valuesMarks . valuesMarks adalah array yang elemennya adalah marks bilangan bulat nilai yang dipancarkan oleh fungsi peta dan dikelompokkan berdasarkan keySubject .Fungsi ini mengurangi valuesMarks array ke jumlah elemennya.

var reducer = function(keySubject, valuesMarks) {
    return Array.sum(valuesMarks);
};

db.student.mapReduce(
    mapper,
    reducer,
    {
        out : "example_results",
        query: { subject : "maths" }       
    }
 );

Dengan koleksi Anda, di atas akan menempatkan hasil agregasi MapReduce Anda dalam koleksi baru db.example_results . Jadi, db.example_results.find() akan menampilkan:

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


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Proyeksi daftar MongoDB dari subbidang

  2. Bagaimana cara menemukan objek yang propertinya foo atau bar sama dengan nilai kueri?

  3. Menemukan catatan mongoDB dalam batch (menggunakan adaptor Ruby mongoid)

  4. Passport.js dan Mongoose.js mengisi Pengguna saat masuk - kehilangan bidang yang terisi di req.user

  5. Indeks Mongodb 2dsphere untuk bidang array bersarang