Dit nuværende skema har marks
feltdatatype som streng, og du skal bruge en heltalsdatatype til din aggregeringsramme for at beregne summen. På den anden side kan du bruge MapReduce
at beregne summen, da det tillader brugen af native JavaScript-metoder såsom parseInt()
på dine objektegenskaber i dets kortfunktioner. Så overordnet har du to valg.
Mulighed 1:Opdater skema (Skift datatype)
Den første ville være at ændre skemaet eller tilføje et andet felt i dit dokument, der har den faktiske numeriske værdi, ikke strengrepræsentationen. Hvis dit samlingsdokument er relativt lille, kan du bruge en kombination af mongodbs markør find()
, forEach()
og update()
metoder til at ændre dit mærkeskema:
db.student.find({ "marks": { "$type": 2 } }).snapshot().forEach(function(doc) {
db.student.update(
{ "_id": doc._id, "marks": { "$type": 2 } },
{ "$set": { "marks": parseInt(doc.marks) } }
);
});
For relativt store samlingsstørrelser vil din db-ydelse være langsom, og det anbefales at bruge mongo-masseopdateringer til dette:
MongoDB-versioner>=2.6 og <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 version 3.2 og nyere:
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);
Mulighed 2:Kør MapReduce
Den anden tilgang ville være at omskrive din forespørgsel med MapReduce
hvor du kan bruge JavaScript-funktionen parseInt()
.
I din MapReduce
operation, definere kortfunktionen, der behandler hvert inputdokument. Denne funktion kortlægger de konverterede marks
strengværdi til subject
for hvert dokument og udsender subject
og konverterede marks
par. Det er her den oprindelige JavaScript-funktion parseInt()
kan anvendes. Bemærk:i funktionen this
refererer til det dokument, som kortreduceringsoperationen behandler:
var mapper = function () {
var x = parseInt(this.marks);
emit(this.subject, x);
};
Dernæst skal du definere den tilsvarende reduktionsfunktion med to argumenter keySubject
og valuesMarks
. valuesMarks
er et array, hvis elementer er heltal marks
værdier udsendt af kortfunktionen og grupperet efter keySubject
. Funktionen reducerer valuesMarks
array til summen af dets elementer.
var reducer = function(keySubject, valuesMarks) {
return Array.sum(valuesMarks);
};
db.student.mapReduce(
mapper,
reducer,
{
out : "example_results",
query: { subject : "maths" }
}
);
Med din samling vil ovenstående placere dit MapReduce-aggregeringsresultat i en ny samling db.example_results
. Således db.example_results.find()
vil udsende:
/* 0 */
{
"_id" : "maths",
"value" : 163
}