Dependiendo de las necesidades de su aplicación, puede usar el marco de agregación para calcular la puntuación y usar bulkWrite()
para actualizar tu colección. Considere el siguiente ejemplo que usa el código <>$proyecto
paso de canalización como margen de maniobra para los cálculos de puntuación con los operadores aritméticos.
Dado que la lógica para calcular C3
en su pregunta está obteniendo un número de 1
a 7
que equivale exactamente a 7 - número de puntos (.)
, el único enfoque factible que se me ocurre es almacenar un campo adicional que contenga este valor antes de realizar la agregación. Entonces, su primer paso sería crear ese campo adicional y puede hacerlo usando el bulkWrite()
de la siguiente manera:
Paso 1:Modifique el esquema para acomodar daysInWeek
adicionales 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, la operación anterior también puede acomodar el cálculo de las otras constantes en su pregunta y, por lo tanto, crear el Field8
como resultado. Sin embargo, creo que se deben realizar cálculos como este en el cliente y dejar que MongoDB haga lo que mejor hace en el servidor.
Paso 2:Use el agregado para agregar Field8
campo
Habiendo creado ese campo adicional daysInWeek
luego puede construir una tubería de agregación que proyecte las nuevas variables utilizando una cohorte de operadores aritméticos
para hacer el cálculo (nuevamente, recomendaría hacer tales cálculos en la capa de aplicación). La proyección final será el producto de los campos calculados que luego puede usar el cursor de resultado agregado para iterar y agregar Field8
a la colección con cada 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); }
Para MongoDB >=2.6
y <=3.0
, use la API de operaciones masivas
donde necesita iterar la colección usando el cursor paraCada()
método, actualice cada documento de la colección.
Algunos de los operadores aritméticos de la canalización de agregación anterior no están disponibles en MongoDB >=2.6
y <=3.0
por lo que deberá realizar los cálculos dentro del paraCada()
iteración.
Use la API masiva para reducir las solicitudes de escritura del servidor al agrupar cada actualización de forma masiva y enviar al servidor solo una vez cada 500 documentos en la colección para su procesamiento:
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(); }