W zależności od potrzeb aplikacji możesz użyć struktury agregacji do obliczenia wyniku i użyć bulkWrite()
aby zaktualizować swoją kolekcję. Rozważmy następujący przykład, który używa kodu <>$projekt
krok potoku jako pole manewru dla obliczeń punktacji za pomocą operatorów arytmetycznych.
Ponieważ logika obliczania C3
w twoim pytaniu otrzymujesz numer od 1
do 7
co równa się dokładnie 7 - liczba punktów (.)
, jedynym możliwym podejściem, jakie przychodzi mi do głowy, jest przechowywanie dodatkowego pola, które przechowuje tę wartość przed wykonaniem agregacji. Więc pierwszym krokiem byłoby utworzenie tego dodatkowego pola i możesz to zrobić za pomocą bulkWrite()
w następujący sposób:
Krok 1:Zmodyfikuj schemat, aby pomieścić dodatkowe daysInWeek
pole
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); }
W idealnym przypadku powyższa operacja może również uwzględniać obliczanie innych stałych w twoim pytaniu, a zatem tworzenie Pola8
w rezultacie. Uważam jednak, że takie obliczenia powinny być wykonywane na kliencie i pozwolić MongoDB robić to, co robi najlepiej na serwerze.
Krok 2:Użyj agregacji, aby dodać Pole8
pole
Po utworzeniu tego dodatkowego pola daysInWeek
następnie możesz skonstruować potok agregacji, który rzutuje nowe zmienne przy użyciu kohorty operatory arytmetyczne
wykonać obliczenia (znowu zalecam wykonywanie takich obliczeń na warstwie aplikacji). Ostateczna projekcja będzie iloczynem obliczonych pól, które można następnie użyć kursora zagregowanego wyniku do iteracji i dodania Pola8
do kolekcji z każdym dokumentem:
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); }
Dla MongoDB >=2.6
i <=3.0
, użyj interfejsu API operacji zbiorczych
gdzie musisz iterować kolekcję za pomocą forEach()
zaktualizuj każdy dokument w kolekcji.
Niektóre operatory arytmetyczne z powyższego potoku agregacji nie są dostępne w MongoDB >=2.6
i <=3.0
więc będziesz musiał wykonać obliczenia w forEach()
iteracja.
Użyj zbiorczego interfejsu API, aby zmniejszyć liczbę żądań zapisu na serwerze, łącząc każdą aktualizację zbiorczo i wysyłając do serwera tylko raz na 500 dokumentów w kolekcji w celu przetworzenia:
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(); }