Uw huidige schema heeft de marks
veldgegevenstype als tekenreeks en u hebt een gegevenstype met een geheel getal nodig voor uw aggregatieraamwerk om de som uit te werken. Aan de andere kant kun je MapReduce
gebruiken om de som te berekenen, aangezien het het gebruik van native JavaScript-methoden zoals parseInt()
. toestaat op uw objecteigenschappen in zijn kaartfuncties. Dus over het algemeen heb je twee keuzes.
Optie 1:schema bijwerken (gegevenstype wijzigen)
De eerste zou zijn om het schema te wijzigen of een ander veld in uw document toe te voegen dat de werkelijke numerieke waarde heeft, niet de tekenreeksrepresentatie. Als uw collectiedocument relatief klein is, kunt u een combinatie van de mongodb-cursor find()
gebruiken , forEach()
en update()
methoden om uw cijferschema te wijzigen:
db.student.find({ "marks": { "$type": 2 } }).snapshot().forEach(function(doc) {
db.student.update(
{ "_id": doc._id, "marks": { "$type": 2 } },
{ "$set": { "marks": parseInt(doc.marks) } }
);
});
Voor relatief grote collecties zullen uw db-prestaties traag zijn en het wordt aanbevolen om mongo bulkupdates hiervoor:
MongoDB-versies>=2.6 en <3.2:
var bulk = db.student.initializeUnorderedBulkOp(),
counter = 0;
db.student.find({"marks": {"$exists": true, "$type": 2 }}).forEach(function (doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "marks": parseInt(doc.marks) }
});
counter++;
if (counter % 1000 === 0) {
// Execute per 1000 operations
bulk.execute();
// re-initialize every 1000 update statements
bulk = db.student.initializeUnorderedBulkOp();
}
})
// Clean up remaining operations in queue
if (counter % 1000 !== 0) bulk.execute();
MongoDB versie 3.2 en nieuwer:
var ops = [],
cursor = db.student.find({"marks": {"$exists": true, "$type": 2 }});
cursor.forEach(function (doc) {
ops.push({
"updateOne": {
"filter": { "_id": doc._id } ,
"update": { "$set": { "marks": parseInt(doc.marks) } }
}
});
if (ops.length === 1000) {
db.student.bulkWrite(ops);
ops = [];
}
});
if (ops.length > 0) db.student.bulkWrite(ops);
Optie 2:MapReduce uitvoeren
De tweede benadering zou zijn om uw zoekopdracht te herschrijven met MapReduce
waar u de JavaScript-functie parseInt()
. kunt gebruiken .
In uw MapReduce
bewerking, definieert u de kaartfunctie die elk invoerdocument verwerkt. Deze functie wijst de geconverteerde marks
toe tekenreekswaarde aan het subject
voor elk document, en zendt het subject
. uit en geconverteerde marks
paar. Dit is waar de JavaScript-native functie parseInt()
kan worden toegepast. Opmerking:in de functie, this
verwijst naar het document dat de bewerking voor het verkleinen van de kaart aan het verwerken is:
var mapper = function () {
var x = parseInt(this.marks);
emit(this.subject, x);
};
Definieer vervolgens de corresponderende reduceerfunctie met twee argumenten keySubject
en valuesMarks
. valuesMarks
is een array waarvan de elementen de integer marks
. zijn waarden uitgezonden door de kaartfunctie en gegroepeerd op keySubject
.De functie reduceert de valuesMarks
array tot de som van de elementen.
var reducer = function(keySubject, valuesMarks) {
return Array.sum(valuesMarks);
};
db.student.mapReduce(
mapper,
reducer,
{
out : "example_results",
query: { subject : "maths" }
}
);
Met uw verzameling zet het bovenstaande uw MapReduce-aggregatieresultaat in een nieuwe verzameling db.example_results
. Dus db.example_results.find()
zal uitvoeren:
/* 0 */
{
"_id" : "maths",
"value" : 163
}