A seconda delle esigenze della tua applicazione, puoi utilizzare il framework di aggregazione per calcolare il punteggio e utilizzare il bulkWrite()
per aggiornare la tua collezione. Considera il seguente esempio che utilizza il $project
passaggio della pipeline come margine per il calcolo del punteggio con gli operatori aritmetici.
Poiché la logica per il calcolo di C3
nella tua domanda sta ottenendo un numero da 1
a 7
che è esattamente 7 - number of points (.)
, l'unico approccio fattibile che mi viene in mente è archiviare un campo aggiuntivo che contenga questo valore prima di eseguire l'aggregazione. Quindi il tuo primo passo sarebbe creare quel campo extra e puoi farlo usando il bulkWrite()
come segue:
Passaggio 1:modifica lo schema per ospitare daysInWeek
extra campo
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); }
Idealmente l'operazione di cui sopra può anche consentire il calcolo delle altre costanti nella tua domanda e quindi la creazione del Field8
di conseguenza. Tuttavia, credo che calcoli come questo dovrebbero essere eseguiti sul client e lasciare che MongoDB faccia ciò che sa fare meglio sul server.
Passaggio 2:utilizza l'aggregato per aggiungere Field8
campo
Dopo aver creato quel campo extra daysInWeek
è quindi possibile costruire una pipeline di aggregazione che proietta le nuove variabili utilizzando una coorte di operatori aritmetici
per eseguire il calcolo (di nuovo, consiglierei di eseguire tali calcoli sul livello dell'applicazione). La proiezione finale sarà il prodotto dei campi calcolati che puoi quindi utilizzare il cursore del risultato aggregato per scorrere e aggiungere Field8
alla raccolta con ogni documento:
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); }
Per MongoDB >= 2.6
e <= 3.0
, utilizza l'API per le operazioni in blocco
dove è necessario iterare la raccolta utilizzando forEach()
metodo, aggiornare ogni documento nella raccolta.
Alcuni degli operatori aritmetici della pipeline di aggregazione sopra non sono disponibili in MongoDB >= 2.6
e <= 3.0
quindi dovrai eseguire i calcoli all'interno di forEach()
iterazione.
Utilizza l'API in blocco per ridurre le richieste di scrittura del server raggruppando ogni aggiornamento in blocco e inviando al server solo una volta ogni 500 documenti nella raccolta per l'elaborazione:
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(); }