Bergantung pada kebutuhan aplikasi Anda, Anda dapat menggunakan kerangka kerja agregasi untuk menghitung skor dan menggunakan bulkWrite()
untuk memperbarui koleksi Anda. Perhatikan contoh berikut yang menggunakan $project
langkah pipa sebagai kelonggaran untuk perhitungan skor dengan operator aritmatika.
Karena logika untuk menghitung C3
dalam pertanyaan Anda mendapatkan nomor dari 1
ke 7
yang sama persis dengan 7 - number of points (.)
, satu-satunya pendekatan yang layak yang dapat saya pikirkan adalah menyimpan bidang tambahan yang menyimpan nilai ini terlebih dahulu sebelum melakukan agregasi. Jadi langkah pertama Anda adalah membuat bidang tambahan itu dan Anda dapat melakukannya menggunakan bulkWrite()
sebagai berikut:
Langkah 1:Ubah skema untuk mengakomodasi daysInWeek
tambahan bidang
var counter = 0, bulkUpdateOps = [];
db.collection1.find({
"Field5": { "$exists": true }
}).forEach(function(doc) {
// calculations for getting the number of points in Field5
var points, daysInWeek;
points = (doc.Field5.match(new RegExp(".", "g")) || []).length;
daysInWeek = 7 - points;
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": {
"$set": { "daysInWeek": daysInWeek }
}
}
});
counter++;
if (counter % 500 == 0) {
db.collection1.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (counter % 500 != 0) { db.collection1.bulkWrite(bulkUpdateOps); }
Idealnya operasi di atas juga dapat mengakomodasi penghitungan konstanta lain dalam pertanyaan Anda dan karenanya membuat Field8
hasil dari. Namun saya percaya perhitungan seperti ini harus dilakukan pada klien dan biarkan MongoDB melakukan yang terbaik di server.
Langkah 2:Gunakan agregat untuk menambahkan Field8
bidang
Setelah membuat bidang ekstra itu daysInWeek
Anda kemudian dapat membuat alur agregasi yang memproyeksikan variabel baru menggunakan kohort operator aritmatika
untuk melakukan perhitungan (sekali lagi, akan merekomendasikan melakukan perhitungan seperti itu pada lapisan aplikasi). Proyeksi akhir akan menjadi produk dari bidang yang dihitung yang kemudian dapat Anda gunakan kursor hasil agregat untuk mengulangi dan menambahkan Field8
ke koleksi dengan setiap dokumen:
var pipeline = [
{
"$project": {
"C1": {
"$add": [
10,
{ "$multiply": [ "$Field3", 0.03 ] }
]
},
"C2": {
"$cond": [
{ "$eq": [ "$Field2", 1 ] },
1,
0.03
]
},
"C3": "$daysInWeek",
"C4": {
"$cond": [
{ "$eq": [ "$Field2", 1 ] },
{ "$pow": [ "$Field4", -0.6 ] },
1
]
}
}
},
{
"$project": {
"Field8": { "$multiply": [ "$C1", "$C2", "$C3", "$C4" ] }
}
}
],
counter = 0,
bulkUpdateOps = [];
db.collection1.aggregate(pipeline).forEach(function(doc) {
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": {
"$set": { "Field8": doc.Field8 }
}
}
});
counter++;
if (counter % 500 == 0) {
db.collection1.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (counter % 500 != 0) { db.collection1.bulkWrite(bulkUpdateOps); }
Untuk MongoDB >= 2.6
dan <= 3.0
, gunakan API Operasi Massal
di mana Anda perlu mengulangi koleksi menggunakan kursor forEach()
metode, perbarui setiap dokumen dalam koleksi.
Beberapa operator aritmatika dari pipa agregasi di atas tidak tersedia di MongoDB >= 2.6
dan <= 3.0
jadi Anda perlu melakukan perhitungan dalam forEach()
iterasi.
Gunakan API massal untuk mengurangi permintaan penulisan server dengan menggabungkan setiap pembaruan secara massal dan mengirim ke server hanya sekali dalam setiap 500 dokumen dalam koleksi untuk diproses:
var bulkUpdateOps = db.collection1.initializeUnorderedBulkOp(),
cursor = db.collection1.find(), // cursor
counter = 0;
cursor.forEach(function(doc) {
// computations
var c1, c2, c3, c4, Field8;
c1 = 10 + (0.03*doc.Field3);
c2 = (doc.Field2 == 1) ? 1: 0.03;
c3 = 7 - (doc.Field5.match(new RegExp(".", "g")) || []).length;
c4 = (doc.Field2 == 1) ? Math.pow(doc.Field, -0.6) : 1;
Field8 = c1*c2*c3*c4;
bulkUpdateOps.find({ "_id": doc._id }).updateOne({
"$set": { "Field8": Field8 }
});
if (counter % 500 == 0) {
bulkUpdateOps.execute();
bulkUpdateOps = db.collection1.initializeUnorderedBulkOp();
}
})
if (counter % 500 != 0) { bulkUpdateOps.execute(); }