Une fonction de réduction peut être appelée une fois, avec une clé et toutes les valeurs correspondantes (mais seulement s'il y a plusieurs valeurs pour la clé - elle ne sera pas appelée du tout s'il n'y a qu'une seule valeur pour la clé).
Il peut également être appelé plusieurs fois, à chaque fois avec une clé et uniquement un sous-ensemble des valeurs correspondantes , et les résultats de réduction précédents pour cette clé. Ce scénario s'appelle une ré-réduction . Afin de prendre en charge les re-réductions, votre fonction de réduction doit être idempotente.
Il existe deux fonctionnalités clés dans une fonction de réduction idempotente :
- La valeur de retour de la fonction de réduction doit être dans le même format que les valeurs Ainsi, si votre fonction reduce accepte un tableau de chaînes, la fonction doit renvoyer une chaîne. S'il accepte des objets avec plusieurs propriétés, il doit retourner un objet contenant ces mêmes propriétés. Cela garantit que la fonction ne s'interrompt pas lorsqu'elle est appelée avec le résultat d'une réduction précédente.
- Ne faites pas d'hypothèses basées sur le nombre de valeurs il prend en compte. Il n'est pas garanti que les
values
le paramètre contient tous les valeurs de la clé donnée. Donc, en utilisantvalues.length
dans les calculs est très risqué et doit être évité.
Mise à jour : Les deux étapes ci-dessous ne sont pas obligatoires (ou même possibles, je n'ai pas vérifié) sur les versions les plus récentes de MongoDB. Il peut maintenant gérer ces étapes pour vous, si vous spécifiez une collection de sortie dans les options map-reduce :
{ out: { reduce: "tempResult" } }
Si votre fonction reduce est idempotente, vous ne devriez avoir aucun problème pour réduire plusieurs collections. Il suffit de re-réduire les résultats de chaque collecte :
Étape 1
Exécutez map-reduce sur chaque collection requise et enregistrez les résultats dans une seule collection temporaire. Vous pouvez stocker les résultats à l'aide d'une fonction de finalisation :
finalize = function (key, value) {
db.tempResult.save({ _id: key, value: value });
}
db.someCollection.mapReduce(map, reduce, { finalize: finalize })
db.anotherCollection.mapReduce(map, reduce, { finalize: finalize })
Étape 2
Exécutez une autre réduction de carte sur la collection temporaire, en utilisant la même fonction de réduction . La fonction map est une fonction simple qui sélectionne les clés et les valeurs de la collection temporaire :
map = function () {
emit(this._id, this.value);
}
db.tempResult.mapReduce(map, reduce)
Cette deuxième réduction de carte est essentiellement une nouvelle réduction et devrait vous donner les résultats dont vous avez besoin.