Allereerst zijn Mongo map/reduce niet ontworpen om te worden gebruikt als een query-tool (zoals het is in CouchDB), het is ontworpen om achtergrondtaken uit te voeren. Ik gebruik het op mijn werk om verkeersgegevens te analyseren.
Wat je echter verkeerd doet, is dat je de sort() op je invoer toepast, maar het is nutteloos omdat wanneer de map()
fase is voltooid, de tussenliggende documenten worden gesorteerd op keys
. Omdat uw sleutel een document is, wordt deze gesorteerd op product_id
, popularity
.
Zo heb ik mijn dataset gegenereerd
function generate_dummy_data() {
for (i=2; i < 1000000; i++) {
db.foobar.save({
_id: i,
category_id: parseInt(Math.random() * 30),
popularity: parseInt(Math.random() * 50)
})
}
}
En dit is mijn kaart/verkleiningstaak:
var data = db.runCommand({
'mapreduce': 'foobar',
'map': function() {
emit({
sorting: this.popularity * -1,
product_id: this._id,
popularity: this.popularity,
}, 1);
},
'reduce': function(key, values) {
var sum = 0;
values.forEach(function(v) {
sum += v;
});
return sum;
},
'query': {category_id: 20},
'out': {inline: 1},
});
En dit is het eindresultaat (heel lang om het hier te plakken):
http://cesarodas.com/results.txt
Dit werkt omdat we nu sorteren op sorting, product_id, popularity
. Je kunt met de sortering spelen zoals je wilt, onthoud alleen dat de uiteindelijke sortering op key
is ongeacht hoe uw invoer is gesorteerd.
Hoe dan ook, zoals ik al eerder zei, je moet voorkomen dat je vragen doet met Map/Reduce, het is ontworpen voor achtergrondverwerking. Als ik jou was, zou ik mijn gegevens zo ontwerpen dat ik er met eenvoudige zoekopdrachten toegang toe zou hebben, in dit geval is er altijd een afweging in dit geval complexe inserts/updates om eenvoudige vragen te hebben (zo zie ik MongoDB).