В зависимост от нуждите на вашето приложение можете да използвате рамката за агрегиране за изчисляване на резултата и да използвате bulkWrite()
за да актуализирате колекцията си. Разгледайте следния пример, който използва $project
стъпка на тръбопровод като свобода на действие за изчисления на резултата с аритметичните оператори.
Тъй като логика за изчисляване на C3
във вашия въпрос е получаване на число от 1
до 7
което е равно точно на 7 - number of points (.)
, единственият възможен подход, за който мога да се сетя, е първо да съхраня допълнително поле, което съдържа тази стойност, преди да извърша агрегирането. Така че първата ви стъпка ще бъде да създадете това допълнително поле и можете да го направите с помощта на bulkWrite()
както следва:
Стъпка 1:Променете схемата, за да побере допълнителни daysInWeek
полето
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); }
В идеалния случай горната операция може също така да поеме изчисляването на другите константи във вашия въпрос и следователно създаването на Field8
като резултат. Въпреки това вярвам, че изчисления като това трябва да се правят на клиента и да оставя MongoDB да прави това, което прави най-добре на сървъра.
Стъпка 2:Използвайте агрегат, за да добавите Field8
полето
След като създадете това допълнително поле daysInWeek
след това можете да конструирате тръбопровод за агрегиране, който проектира новите променливи с помощта на кохорта от аритметични оператори
за извършване на изчислението (отново бихме препоръчали извършването на такива изчисления на приложния слой). Крайната проекция ще бъде продуктът на изчислените полета, които след това можете да използвате курсора на обобщения резултат, за да повторите и добавите Field8
към колекцията с всеки документ:
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); }
За MongoDB >= 2.6
и <= 3.0
, използвайте API за групови операции
където трябва да итерирате колекцията, като използвате forEach()
метод, актуализирайте всеки документ в колекцията.
Някои от аритметичните оператори от горния конвейер за агрегиране не са налични в MongoDB >= 2.6
и <= 3.0
така че ще трябва да направите изчисленията в рамките на forEach()
итерация.
Използвайте груповия API, за да намалите заявките за запис на сървъра, като групирате всяка актуализация групово и изпращате до сървъра само веднъж на всеки 500 документа в колекцията за обработка:
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(); }