Функция приведения может быть вызвана один раз, с ключом и всеми соответствующими значениями (но только при наличии нескольких значений для ключа - она не будет вызываться вообще, если есть только 1 значение для ключ).
Он также может вызываться несколько раз, каждый раз с ключом и только подмножеством соответствующих значений , и предыдущий результат уменьшения для этого ключа. Этот сценарий называется повторным сокращением . Для поддержки повторного сокращения ваша функция уменьшения должна быть идемпотентной .
В идемпотентной функции уменьшения есть две ключевые особенности:
- Возвращаемое значение функции Reduce должно быть в том же формате , что и значения , которые она принимает. Так что, если ваша функция Reduce принимает массив строк, функция должна вернуть строку. Если он принимает объекты с несколькими свойствами, он должен возвращать объект, содержащий те же свойства. Это гарантирует, что функция не прервется при вызове с результатом предыдущего сокращения.
- Не делайте предположений, основываясь на количестве значений , которое он принимает. Не гарантируется, что параметр
values
содержит все значения для данного ключа. Поэтому использование values.length
в расчетах очень рискованно, и его следует избегать.
Обновление: Два последних шага не являются обязательными (или даже невозможными, я не проверял) в последних версиях MongoDB. Теперь он может обработать эти шаги для вас, если вы укажете выходную коллекцию в map-limit options :
{ out: { reduce: "tempResult" } }
Если ваша функция сокращения идемпотентна, у вас не должно возникнуть проблем с уменьшением карты нескольких коллекций. Просто уменьшите результаты каждой коллекции:
Шаг 1
Запустите map-reduction для каждой требуемой коллекции и сохраните результаты в одной временной коллекции. Вы можете сохранить результаты, используя функцию финализации :
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 })
Шаг 2
Запустите другую карту-уменьшение для временной коллекции, , используя ту же функцию уменьшения . Функция map - это простая функция, которая выбирает ключи и значения из временной коллекции:
map = function () {
emit(this._id, this.value);
}
db.tempResult.mapReduce(map, reduce)
Это второе уменьшение карты, по сути, является повторным уменьшением и должно дать вам необходимые результаты.