Beroende på dina applikationsbehov kan du använda aggregeringsramverket för att beräkna poängen och använda bulkWrite()
för att uppdatera din samling. Tänk på följande exempel som använder
Sedan logik för att beräkna C3
i din fråga får du ett nummer från 1
till 7
vilket är lika med exakt 7 - antal poäng (.)
, det enda möjliga tillvägagångssättet jag kan komma på är att lagra ett extra fält som håller detta värde först innan du gör aggregeringen. Så ditt första steg skulle vara att skapa det extra fältet och du kan göra det med bulkWrite()
enligt följande:
Steg 1:Ändra schemat för att ta emot extra daysInWeek
fält
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); }
Helst kan ovanstående operation också anpassas till att beräkna de andra konstanterna i din fråga och därför skapa Field8
som ett resultat. Men jag tror att beräkningar som detta bör göras på klienten och låta MongoDB göra vad den gör bäst på servern.
Steg 2:Använd aggregering för att lägga till Fält8
fält
Efter att ha skapat det extra fältet daysInWeek
du kan sedan konstruera en aggregeringspipeline som projicerar de nya variablerna med hjälp av en kohort av aritmetiska operatorer
att göra beräkningen (återigen, skulle rekommendera att göra sådana beräkningar på applikationslagret). Den slutliga projektionen kommer att vara produkten av de beräknade fälten som du sedan kan använda den samlade resultatmarkören för att iterera och lägga till Fält8
till samlingen med varje dokument:
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); }
För MongoDB >=2.6
och <=3.0
, använd Bulk Operations API
där du behöver upprepa samlingen med markörens forEach()
metod, uppdatera varje dokument i samlingen.
Vissa av de aritmetiska operatorerna från ovanstående aggregeringspipeline är inte tillgängliga i MongoDB >=2.6
och <=3.0
så du måste göra beräkningarna inom forEach()
iteration.
Använd bulk-API:et för att minska serverskrivbegäranden genom att bunta varje uppdatering i bulk och skicka till servern endast en gång av 500 dokument i samlingen för bearbetning:
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(); }