Selon les besoins de votre application, vous pouvez utiliser le cadre d'agrégation pour calculer le score et utiliser le bulkWrite()
pour mettre à jour votre collection. Prenons l'exemple suivant qui utilise le $project
étape du pipeline comme marge de manœuvre pour les calculs de score avec les opérateurs arithmétiques.
Puisque la logique de calcul de C3
dans votre question obtient un nombre de 1
à 7
qui est exactement égal à 7 - number of points (.)
, la seule approche réalisable à laquelle je peux penser est de stocker un champ supplémentaire contenant cette valeur avant de procéder à l'agrégation. Donc, votre première étape serait de créer ce champ supplémentaire et vous pouvez le faire en utilisant le bulkWrite()
comme suit :
Étape 1 :Modifier le schéma pour accepter des daysInWeek
supplémentaires champ
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); }
Idéalement, l'opération ci-dessus peut également permettre de calculer les autres constantes de votre question et donc de créer le Field8
par conséquent. Cependant, je pense que des calculs comme celui-ci devraient être effectués sur le client et laisser MongoDB faire ce qu'il fait le mieux sur le serveur.
Étape 2 :Utilisez l'agrégation pour ajouter Field8
champ
Après avoir créé ce champ supplémentaire daysInWeek
vous pouvez ensuite construire un pipeline d'agrégation qui projette les nouvelles variables à l'aide d'une cohorte de opérateurs arithmétiques
pour faire le calcul (encore une fois, je recommanderais de faire de tels calculs sur la couche application). La projection finale sera le produit des champs calculés que vous pourrez ensuite utiliser le curseur de résultat agrégé pour itérer et ajouter Field8
à la collection avec chaque document :
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); }
Pour MongoDB >= 2.6
et <= 3.0
, utilisez l'l'API des opérations en masse
où vous devez itérer la collection en utilisant le forEach()
, mettez à jour chaque document de la collection.
Certains des opérateurs arithmétiques du pipeline d'agrégation ci-dessus ne sont pas disponibles dans MongoDB >= 2.6
et <= 3.0
vous devrez donc effectuer les calculs dans le forEach()
itération.
Utilisez l'API en bloc pour réduire les demandes d'écriture du serveur en regroupant chaque mise à jour en bloc et en envoyant au serveur une seule fois tous les 500 documents de la collection pour traitement :
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(); }