Tout d'abord, Mongo map/reduce n'est pas conçu pour être utilisé comme outil de requête (comme c'est le cas dans CouchDB), il est conçu pour vous permettre d'exécuter des tâches en arrière-plan. Je l'utilise au travail pour analyser les données de trafic.
Ce que vous faites de mal, cependant, c'est que vous appliquez le sort() à votre entrée, mais cela ne sert à rien car lorsque le map()
l'étape est terminée les documents intermédiaires sont triés par chaque keys
. Comme votre clé est un document, elle est triée par product_id
, popularity
.
Voici comment j'ai généré mon jeu de données
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)
})
}
}
Et voici ma tâche map/reduce :
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},
});
Et voici le résultat final (très long à coller ici) :
http://cesarodas.com/results.txt
Cela fonctionne car maintenant nous trions par sorting, product_id, popularity
. Vous pouvez jouer avec le tri comme bon vous semble, rappelez-vous simplement que le tri final se fait par keys
quelle que soit la manière dont vos entrées sont triées.
Quoi qu'il en soit, comme je l'ai déjà dit, évitez de faire des requêtes avec Map/Reduce, il a été conçu pour le traitement en arrière-plan. Si j'étais vous, je concevrais mes données de manière à pouvoir y accéder avec des requêtes simples, il y a toujours un compromis dans ce cas d'insertion/mises à jour complexes pour avoir des requêtes simples (c'est comme ça que je vois MongoDB).