db.collection.mapReduce()

在本页面

Note

Views不支持 map-reduce 操作。

db.collection.mapReduce()具有以下语法:

db.collection.mapReduce(
                         <map>,
                         <reduce>,
                         {
                           out: <collection>,
                           query: <document>,
                           sort: <document>,
                           limit: <number>,
                           finalize: <function>,
                           scope: <document>,
                           jsMode: <boolean>,
                           verbose: <boolean>,
                           bypassDocumentValidation: <boolean>
                         }
                       )

db.collection.mapReduce()采用以下参数:

ParameterTypeDescription
mapfunction一个将valuekey关联或“Map”并发出key和值pair的 JavaScript 函数。


有关更多信息,请参见Map 功能要求
| reduce | function | JavaScript 函数,将与特定key关联的所有values“减少”到单个对象。
有关更多信息,请参见化简功能的要求
| options | document |一个文档,它指定db.collection.mapReduce()的附加参数。
| bypassDocumentValidation |布尔值|可选。使mapReduce在操作过程中绕过文档验证。这使您可以插入不符合验证要求的文档。
版本 3.2 中的新功能。

下表描述了db.collection.mapReduce()可以接受的其他参数。

FieldTypeDescription
out字符串或文件指定 Map 归约运算结果的位置。您可以输出到集合,使用操作输出到集合或内联输出。对集合的主要成员执行 map-reduce 操作时,您可以输出到集合。在secondary个成员上,您只能使用inline输出。


有关更多信息,请参见out Options
| query | document |使用query operators指定选择标准,以确定 Importing 到map功能的文档。
| sort | document |对* input *文档进行排序。此选项对于优化很有用。例如,将排序键指定为与运行键相同,以便减少还原操作。排序键必须在此集合的现有索引中。
| limit |数字|指定用于 Importingmap函数的最大文档数。
| finalize |功能|可选。遵循reduce方法并修改输出。
有关更多信息,请参见完成功能的要求
| scope | document |指定可在mapreducefinalize函数中访问的全局变量。
| jsMode |布尔值|指定在执行mapreduce函数之间是否将中间数据转换为 BSON 格式。
默认为false
如果false
在内部,MongoDB 将map函数发出的 JavaScript 对象转换为 BSON 对象。然后,在调用reduce函数时,这些 BSON 对象将转换回 JavaScript 对象。
Map 减少操作将中间 BSON 对象放置在磁盘上的临时存储中。这允许 map-reduce 操作在任意大的数据集上执行。
如果true
在内部,在map函数期间发出的 JavaScript 对象保留为 JavaScript 对象。无需为reduce函数转换对象,这可以加快执行速度。
您只能对 Map 器的emit()函数使用少于 500,000 个不同的key参数的结果集使用jsMode
| verbose |布尔值|指定结果信息中是否包含timing信息。将verbose设置为true以包含timing信息。
默认为false
| collation |文档|可选。
指定用于操作的collation
Collation允许用户为字符串比较指定特定于语言的规则,例如字母大写和重音符号的规则。
排序规则选项具有以下语法:
collation: {
locale: <string>,
caseLevel: <boolean>,
caseFirst: <string>,
strength: <int>,
numericOrdering: <boolean>,
alternate: <string>,
maxVariable: <string>,
backwards: <boolean>
}
指定排序规则时,locale字段为必填字段;所有其他排序规则字段都是可选的。有关字段的说明,请参见Collation Document
如果未指定排序规则,但是集合具有默认排序规则(请参见db.createCollection()),则该操作将使用为集合指定的排序规则。
如果没有为集合或操作指定排序规则,则 MongoDB 使用先前版本中使用的简单二进制比较进行字符串比较。
您不能为一个操作指定多个排序规则。例如,您不能为每个字段指定不同的排序规则,或者如果对排序执行查找,则不能对查找使用一种排序规则,而对排序使用另一种排序规则。
3.4 版中的新功能。

Note

map-reduce operationsgroup命令和$where运算符表达式**无法访问mongoShell 程序中可用的某些全局函数或属性,例如db

下列 JavaScript 函数和属性**可用于map-reduce operationsgroup命令和$where运算符表达式:

Available PropertiesAvailable Functions
args


> MaxKey

> MinKey|assert()

> BinData()

> DBPointer()

> DBRef()

> doassert()

> emit()

> gc()

> HexData()

> hex_md5()

> isNumber()

> isObject()

> ISODate()

> isString()|Map()

> MD5()

> NumberInt()

> NumberLong()

> ObjectId()

> print()

> printjson()

> printjsononeline()

> sleep()

> Timestamp()

> tojson()

> tojsononeline()

> tojsonObject()

> UUID()

> version()|

Map 功能要求

map函数负责将每个 Importing 文档转换为零个或多个文档。它可以访问scope参数中定义的变量,并具有以下原型:

function() {
   ...
   emit(key, value);
}

map函数具有以下要求:

  • map函数中,在函数中以this引用当前文档。

  • map函数不应出于任何原因不能访问数据库。

  • map函数应该是纯函数,或者对函数外部没有任何影响(即副作用)。

  • 一次运行只能容纳 MongoDB BSON 文档的最大大小的一半。

  • map函数可以选择调用emit(key,value)任意次,以创建将keyvalue关联的输出文档。

以下map函数将根据 Importing 文档的status字段的值调用emit(key,value) 0 或 1 次:

function() {
    if (this.status == 'A')
        emit(this.cust_id, 1);
}

以下map函数可能会多次调用emit(key,value),具体取决于 Importing 文档的items字段中的元素数量:

function() {
    this.items.forEach(function(item){ emit(item.sku, 1); });
}

reduce 函数的要求

reduce函数具有以下原型:

function(key, values) {
   ...
   return result;
}

reduce函数具有以下行为:

  • reduce函数不应即使也不能执行读取操作。

  • reduce函数应该影响外部系统。

  • MongoDB 将“不”调用仅具有单个值的键的reduce函数。 values参数是一个数组,其元素是“Map”到keyvalue对象。

  • MongoDB 可以为同一键多次调用reduce函数。在这种情况下,该键的reduce函数的先前输出将成为该键的下一个reduce函数调用的 Importing 值之一。

  • reduce函数可以访问scope参数中定义的变量。

  • reduce的 Importing 不得大于 MongoDB BSON 文档的最大大小的一半。当返回大文档然后在随后的reduce步骤中将它们合并在一起时,可能会违反此要求。

因为可以为同一键多次调用reduce函数,所以以下属性必须为 true:

  • 返回对象的* type *必须与map函数发出的value的类型相同。

  • reduce函数必须是* associative *。以下 Statements 必须为真:

reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] )
  • reduce函数必须是幂等。确保以下语句为真:
reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray )
  • reduce函数应该是“可交换的”:即valuesArray中元素的 Sequences 不应影响reduce函数的输出,因此以下语句为真:
reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )

out Options

您可以为out参数指定以下选项:

输出到集合

此选项输出到新集合,在副本集的辅助成员上不可用。

out: <collectionName>

通过操作输出到集合

仅当将已经存在的集合传递给out时,此选项才可用。在副本集的辅助成员上不可用。

out: { <action>: <collectionName>
        [, db: <dbName>]
        [, sharded: <boolean> ]
        [, nonAtomic: <boolean> ] }

当您通过操作输出到集合时,out具有以下参数:

  • <action>:指定以下操作之一:

  • replace

如果存在带有<collectionName>的集合,请替换<collectionName>的内容。

  • merge

如果输出集合已经存在,则将新结果与现有结果合并。如果现有文档的密钥与新结果相同,则“覆盖”该现有文档。

  • reduce

如果输出集合已经存在,则将新结果与现有结果合并。如果现有文档的键与新结果相同,则对新文档和现有文档都应用reduce函数,并用结果覆盖现有文档。

  • db :

可选的。您希望 map-reduce 操作写入其输出的数据库的名称。默认情况下,该数据库将与 Importing 集合相同。

  • sharded :

可选的。如果true 并且已在输出数据库上启用分片,则 map-reduce 操作将使用_id字段作为分片键对输出集合进行分片。

如果truecollectionName是现有的未分片集合,则 map-reduce 失败。

  • nonAtomic :

可选的。将输出操作指定为非原子操作。这仅适用于mergereduce输出模式,这可能需要几分钟才能执行。

默认情况下,nonAtomicfalse,并且 map-reduce 操作在后处理期间锁定数据库。

如果nonAtomictrue,则后处理步骤将阻止 MongoDB 锁定数据库:在此期间,其他 Client 端将能够读取输出集合的中间状态。

Output Inline

在内存中执行 map-reduce 操作并返回结果。此选项是副本集的辅助成员上out的唯一可用选项。

out: { inline: 1 }

结果必须符合BSON 文档的最大尺寸

完成函数的要求

finalize函数具有以下原型:

function(key, reducedValue) {
   ...
   return modifiedObject;
}

finalize函数从reduce函数接收key值和reducedValue作为其参数。意识到:

  • finalize函数不应出于任何原因不能访问数据库。

  • finalize函数应该是纯函数,或者对函数外部没有任何影响(即副作用)。

  • finalize函数可以访问scope参数中定义的变量。

Map-Reduce Examples

请考虑对包含以下原型文档的集合orders进行以下 map-reduce 操作:

{
     _id: ObjectId("50a8240b927d5d8b5891743c"),
     cust_id: "abc123",
     ord_date: new Date("Oct 04, 2012"),
     status: 'A',
     price: 25,
     items: [ { sku: "mmm", qty: 5, price: 2.5 },
              { sku: "nnn", qty: 5, price: 2.5 } ]
}

返回每个 Client 的总价

orders集合执行 map-reduce 操作以对cust_id进行分组,并为每个cust_id计算price的总和:

  • 定义 Map 功能来处理每个 Importing 文档:

  • 在函数中,this表示正在执行 map-reduce 操作的文档。

  • 该函数将每个文档的priceMap 到cust_id并发出cust_idprice对。

var mapFunction1 = function() {
                       emit(this.cust_id, this.price);
                   };
  • 使用两个参数keyCustIdvaluesPrices定义相应的 reduce 函数:

  • valuesPrices是一个数组,其元素是 map 函数发出的price值,并按keyCustId分组。

  • 该函数将valuesPrice数组减少为其元素的总和。

var reduceFunction1 = function(keyCustId, valuesPrices) {
                          return Array.sum(valuesPrices);
                      };
  • 使用mapFunction1 map 函数和reduceFunction1 reduce 函数对orders集合中的所有文档执行 map-reduce。
db.orders.mapReduce(
                     mapFunction1,
                     reduceFunction1,
                     { out: "map_reduce_example" }
                   )

此操作将结果输出到名为map_reduce_example的集合。如果map_reduce_example集合已经存在,则该操作将使用此 map-reduce 操作的结果替换内容:

计算订单和总数量以及每件商品的平均数量

在此示例中,您将对orders集合上所有ord_date值大于01/01/2012的文档执行 map-reduce 操作。工序按item.sku字段分组,并计算每个sku的订单数量和总 Order 量。通过计算每个sku值的每个订单的平均数量来结束该操作:

  • 定义 Map 功能来处理每个 Importing 文档:

  • 在函数中,this表示正在执行 map-reduce 操作的文档。

  • 对于每个项目,该函数将sku与新对象value关联,该对象包含1count和订单的项目qty并发出skuvalue对。

var mapFunction2 = function() {
                       for (var idx = 0; idx < this.items.length; idx++) {
                           var key = this.items[idx].sku;
                           var value = {
                                         count: 1,
                                         qty: this.items[idx].qty
                                       };
                           emit(key, value);
                       }
                    };
  • 使用两个参数keySKUcountObjVals定义相应的 reduce 函数:

  • countObjVals是一个数组,其元素是 Map 到由 map 函数传递给 reducer 函数的分组的keySKU值的对象。

  • 该函数将countObjVals数组简化为包含countqty字段的单个对象reducedValue

  • reducedVal中,count字段包含单个数组元素中count字段的总和,qty字段包含单个数组元素中qty字段的总和。

var reduceFunction2 = function(keySKU, countObjVals) {
                     reducedVal = { count: 0, qty: 0 };

                     for (var idx = 0; idx < countObjVals.length; idx++) {
                         reducedVal.count += countObjVals[idx].count;
                         reducedVal.qty += countObjVals[idx].qty;
                     }

                     return reducedVal;
                  };
  • 用两个参数keyreducedVal定义一个 finalize 函数。该函数修改reducedVal对象以添加一个名为avg的计算字段,并返回修改后的对象:
var finalizeFunction2 = function (key, reducedVal) {

                       reducedVal.avg = reducedVal.qty/reducedVal.count;

                       return reducedVal;

                    };
  • 使用mapFunction2reduceFunction2finalizeFunction2函数对orders集合执行 map-reduce 操作。
db.orders.mapReduce( mapFunction2,
                     reduceFunction2,
                     {
                       out: { merge: "map_reduce_example" },
                       query: { ord_date:
                                  { $gt: new Date('01/01/2012') }
                              },
                       finalize: finalizeFunction2
                     }
                   )

此操作使用query字段仅选择ord_date大于new Date(01/01/2012)的那些文档。然后将结果输出到集合map_reduce_example。如果map_reduce_example集合已经存在,则该操作会将现有内容与该 map-reduce 操作的结果合并。

Output

db.collection.mapReduce()方法的输出与mapReduce命令的输出相同。有关db.collection.mapReduce()输出的信息,请参见mapReduce命令的Output部分。

Additional Information