На първо място, Mongo map/reduce не са предназначени да се използват като инструмент за заявки (както е в CouchDB), те са предназначени да изпълнявате фонови задачи. Използвам го на работа, за да анализирам данни за трафика.
Това, което правите погрешно обаче е, че прилагате sort() към вашия вход, но е безполезен, защото когато map()
етапът е завършен, междинните документи се сортират по всеки keys
. Тъй като вашият ключ е документ, той се сортира по product_id
, popularity
.
Ето как генерирах моя набор от данни
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)
})
}
}
И това е моята задача за карта/намаляване:
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},
});
И това е крайният резултат (много дълго, за да го поставите тук):
http://cesarodas.com/results.txt
Това работи, защото сега сортираме по sorting, product_id, popularity
. Можете да играете със сортирането, както искате, просто не забравяйте, че окончателното сортиране е по keys
независимо от вас как е сортирано въведеното ви.
Както и да е, както казах преди, трябва да избягвате да правите заявки с Map/Reduce, той е проектиран за фонова обработка. Ако бях на твое място, щях да проектирам данните си по такъв начин, че да мога да получа достъп до тях с прости заявки, винаги има компромис в този случай сложни вмъквания/актуализации, за да има прости заявки (така виждам MongoDB).