Observação
Pipeline de Agregação como Alternativa à Redução de Mapa
A partir do MongoDB , 5.0, map-reduce está obsoleto:
Em vez de map-reduce, você deve usar um aggregation pipeline. aggregation pipeline fornece melhor desempenho e usabilidade do que a redução de mapa.
Você pode reescrever operações de redução de mapa utilizando estágios do pipeline de agregação, como
$group,$mergee outros.Nas operações de map-reduce que exigem funcionalidade personalizada, você pode usar os operadores de agregação
$accumulatore$function. Você pode usar esses operadores para definir expressões de agregação personalizadas no JavaScript.
Para obter exemplos de alternativas de aggregation pipeline para map-reduce, consulte:
Definição
mapReduceO comando
mapReducepermite que você execute operações de agregação de map-reduce em uma coleção.Dica
Em
mongosh, esse comando também pode ser executado por meio do método auxiliarmapReduce().Os métodos auxiliares são práticos para os usuários
mongosh, mas podem não retornar o mesmo nível de informações que os comandos do banco de dados. Nos casos em que a praticidade não for necessária ou os campos de retorno adicionais forem necessários, use o comando de banco de dados.
Compatibilidade
Esse comando está disponível em implantações hospedadas nos seguintes ambientes:
MongoDB Atlas: o serviço totalmente gerenciado para implantações do MongoDB na nuvem
Importante
Este comando não é suportado em clusters M0, M2 e M5 . Para obter mais informações, consulte Comandos não suportados.
MongoDB Enterprise: a versão autogerenciada e baseada em assinatura do MongoDB
MongoDB Community: uma versão com código disponível, de uso gratuito e autogerenciada do MongoDB
Sintaxe
Observação
O MongoDB ignora a opção verbose.
A partir da versão 4.2, o MongoDB descontinuará:
A opção map-reduce para criar uma nova coleção fragmentada, bem como o uso da opção fragmentada para map-reduce. Para gerar saída para uma coleção fragmentada, crie primeiro a coleção fragmentada. O MongoDB 4.2 também descontinua a substituição de uma coleção fragmentada existente.
O comando mapReduce tem a seguinte sintaxe:
db.runCommand( { mapReduce: <string>, map: <string or JavaScript>, reduce: <string or JavaScript>, finalize: <string or JavaScript>, out: <output>, query: <document>, sort: <document>, limit: <number>, scope: <document>, jsMode: <boolean>, verbose: <boolean>, bypassDocumentValidation: <boolean>, collation: <document>, maxTimeMS: <integer>, writeConcern: <document>, comment: <any> } )
Campos de comando
O comando usa os seguintes campos como argumentos:
Campo | Tipo | Descrição | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
string | O nome da collection na qual você deseja executar a redução de mapa. Essa coleção será filtrada usando As visualizações não suportam operações de redução de mapa. | |||||||||||
Javascript ou string | Uma função JavaScript que associa ou "mapeia" um Para obter mais informações, consulte Requisitos para a função de mapa. | |||||||||||
Javascript ou string | Uma função JavaScript que "reduz" a um único objeto todos os Para obter mais informações, consulte Requisitos para a função de redução. | |||||||||||
string ou documento | Especifica onde produzir o resultado da operação map-reduce. Você pode gerar saída para uma collection ou retornar o resultado in-line. Em um membro primário de um conjunto de réplicas, você pode gerar resultados para uma collection ou in-line, mas somente resultados in-line são possíveis em um secundário. Para obter mais informações,consulte Opções de out. | |||||||||||
documento | Opcional. Especifica os critérios de seleção utilizando operadores de query para determinar a entrada de documentos para a função | |||||||||||
documento | Opcional. Classifica os documentos de entrada. Esta opção é útil para otimização. Por exemplo, especifique que a chave de classificação deve ser igual à chave de emissão para que haja menos operações de redução. A chave de classificação deve estar em um índice existente para essa collection. | |||||||||||
número | Opcional. Especifica um número máximo de documentos para a entrada na função | |||||||||||
Javascript ou string | Opcional. Uma função JavaScript que modifica a saída após a função Para obter mais informações, consulte Requisitos para a função de finalização. | |||||||||||
documento | Opcional. Especifica variáveis globais que são acessíveis nas funções | |||||||||||
booleano | Opcional. Especifica se serão convertidos dados intermediários em formato BSON entre a execução das funções Padrão é Se
Se
| |||||||||||
booleano | Opcional. Especifica se as informações de Padrão é Esta opção é ignorada. As informações do resultado sempre excluem as informações de | |||||||||||
booleano | Opcional. Habilita o Se a opção de saída estiver definida | |||||||||||
documento | Opcional. Especifica o agrupamento a ser usado para a operação. A colocação permite que os usuários especifiquem regras específicas do idioma para comparação de strings, como regras para letras maiúsculas e marcas de acento. A opção de agrupamento tem a seguinte sintaxe: Ao especificar agrupamento, o campo Se o agrupamento não for especificado, mas a coleção tiver um agrupamento padrão (consulte Se nenhum agrupamento for especificado para a coleção ou para as operações, o MongoDB usa a comparação binária simples usada nas versões anteriores para comparações de strings. Você não pode especificar vários agrupamentos para uma operação. Por exemplo, você não pode especificar agrupamentos diferentes por campo ou, se estiver realizando uma busca com uma classificação, não poderá usar um agrupamento para a busca e outro para a classificação. Novidade na versão 3.4. | |||||||||||
| non-negative integer | Opcional. Especifica um limite de tempo em milissegundos. Se você não especificar um valor para O MongoDB encerra as operações que excedem o limite de tempo alocado usando o mesmo mecanismo de | ||||||||||
documento | Opcional. Um documento que expressa a write concern a ser usada ao gerar saída para uma collection. Omite o uso da write concern padrão. | |||||||||||
| any | Opcional. Um comentário fornecido pelo usuário para anexar a este comando. Depois de definido, esse comentário aparece junto com os registros desse comando nos seguintes locais:
Um comentário pode ser qualquer tipo BSON válido (string, inteiro, objeto, array etc). |
Uso
O seguinte é um uso experimental do comando mapReduce:
var mapFunction = function() { ... }; var reduceFunction = function(key, values) { ... }; db.runCommand( { mapReduce: <input-collection>, map: mapFunction, reduce: reduceFunction, out: { merge: <output-collection> }, query: <query> } )
Observação
JavaScript no MongoDB
Embora mapReduce utilize JavaScript, esse não é o caso da maioria das interações com o MongoDB. O driver idiomático na linguagem do aplicativo de interação é usado com mais frequência.
Requisitos para a map função
A função map é responsável por transformar cada documento de entrada em zero ou mais documentos. Ela pode acessar as variáveis definidas no parâmetro scope e tem o seguinte protótipo:
function() { ... emit(key, value); }
A função map tem os seguintes requisitos:
Na função
map, referencie o documento atual comothisdentro da função.A função
mapnão deve acessar o banco de dados por nenhum motivo.A função
mapdeve ser pura ou não impacto fora dela (ou seja, efeitos colaterais).A função
mappode, opcionalmente, chamaremit(key,value)várias vezes para criar um documento de saída associandokeyavalue.
A função map a seguir chamará emit(key,value) 0 ou 1 vez, dependendo do valor do campo status do documento de entrada:
function() { if (this.status == 'A') emit(this.cust_id, 1); }
A função map a seguir pode chamar emit(key,value) várias vezes, dependendo do número de elementos no campo items do documento de entrada:
function() { this.items.forEach(function(item){ emit(item.sku, 1); }); }
Requisitos para a reduce função
A função reduce tem o seguinte protótipo:
function(key, values) { ... return result; }
A função reduce exibe os seguintes comportamentos:
A função
reducenão deve acessar o banco de dados, mesmo para realizar operações de leitura.A função
reducenão deve afetar o sistema externo.O MongoDB pode invocar a função
reducemais de uma vez para a mesma chave. Neste caso, a saída anterior da funçãoreducepara esta chave se tornará um dos valores de entrada para a próxima invocação da funçãoreducepara esta chave.A função
reducepode acessar as variáveis definidas no parâmetroscope.As entradas para
reducenão devem ser maiores que a metade do tamanho máximo do documento BSON do MongoDB. Esse requisito pode ser violado quando documentos grandes são devolvidos e, em seguida, unidos emreduceetapas subsequentes.
Como é possível invocar a função reduce mais de uma vez para a mesma chave, as seguintes propriedades precisam ser verdadeiras:
o tipo do objeto de retorno deve ser idêntico ao tipo do
valueemitido pela funçãomap.a função
reducedeve ser associativa. A seguinte declaração deve ser verdadeira:reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] ) a função
reducedeve ser idempotente. Confirme se a afirmação a seguir é verdadeira:reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray ) a função
reducedeve ser comutativa, isto é, a ordem dos elementos novaluesArraynão deve afetar a saída da funçãoreduce, de forma que a seguinte declaração seja verdadeira:reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )
Requisitos para a finalize função
A função finalize tem o seguinte protótipo:
function(key, reducedValue) { ... return modifiedObject; }
A função finalize recebe como seus argumentos um valor key e reducedValue da função reduce. Esteja ciente de que:
A função
finalizenão deve acessar o banco de dados por nenhum motivo.A função
finalizedeve ser pura ou não impacto fora dela (ou seja, efeitos colaterais).A função
finalizepode acessar as variáveis definidas no parâmetroscope.
out Opções
Você pode especificar as seguintes opções para o parâmetro out:
Saída para uma collection
Esta opção gera resultados para uma nova collection e não está disponível para membros secundários de conjuntos de réplicas.
out: <collectionName>
Saída para uma collection com uma ação
Observação
A partir da versão 4.2, o MongoDB descontinuará:
A opção map-reduce para criar uma nova coleção fragmentada, bem como o uso da opção fragmentada para map-reduce. Para gerar saída para uma coleção fragmentada, crie primeiro a coleção fragmentada. O MongoDB 4.2 também descontinua a substituição de uma coleção fragmentada existente.
Esta opção só está disponível ao passar uma collection que já existe para out. Não está disponível para membros secundários de conjuntos de réplicas.
out: { <action>: <collectionName> [, db: <dbName>] [, sharded: <boolean> ] }
Quando você gera resultados para uma coleção com uma ação, o out tem os seguintes parâmetros:
<action>: especifique uma das seguintes ações:replaceSubstitua o conteúdo de
<collectionName>se a collection com<collectionName>existir.mergeMescle o novo resultado com o resultado existente se a collection de saída já existir. Se um documento existente tiver a mesma chave que o novo resultado, substitua esse documento existente.
reduceMescle o novo resultado com o resultado existente se a collection de saída já existir. Se um documento existente tiver a mesma chave que o novo resultado, aplique a função
reduceaos documentos novo e existente e substitua o documento existente pelo resultado.
db:Opcional. O nome do banco de dados em que você deseja que a operação map-reduce escreva sua saída. Por padrão, este será o mesmo banco de dados que a collection de entrada.
Gerar saída in-line
Execute a operação map-reduce na memória e retorne o resultado. Esta opção é a única disponível para out em membros secundários de conjuntos de réplicas.
out: { inline: 1 }
O resultado deve caber no tamanho máximo de um documento BSON.
Acesso necessário
Se sua implantação MongoDB forçar autenticação, o usuário executando o comando mapReduce deverá ter as seguintes ações de privilégio:
Map-reduce com opção de saída {out : inline}:
Map-reduce com a ação replace ao enviar para uma collection:
Map-reduce com as ações merge ou reduce ao enviar para uma collection:
A função integrada readWrite fornece as permissões necessárias para executar a aggregation de map-reduce.
Restrições
O comando mapReduce não mais compatível com afterClusterTime. Então, mapReduce não pode ser associada a sessões causalmente consistentes.
Exemplos de map-reduce
No mongosh, o método db.collection.mapReduce() é um encapsulador do comando mapReduce. Os exemplos a seguir utilizam o método db.collection.mapReduce():
Os exemplos nesta seção incluem alternativas de aggregation pipelines sem expressões de agregação customizadas. Para alternativas que usam expressões personalizadas, consulte Exemplos de tradução do map-reduce para o aggregation pipeline.
Crie uma coleção de amostra orders com estes documentos:
db.orders.insertMany([ { _id: 1, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-01"), price: 25, items: [ { sku: "oranges", qty: 5, price: 2.5 }, { sku: "apples", qty: 5, price: 2.5 } ], status: "A" }, { _id: 2, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-08"), price: 70, items: [ { sku: "oranges", qty: 8, price: 2.5 }, { sku: "chocolates", qty: 5, price: 10 } ], status: "A" }, { _id: 3, cust_id: "Busby Bee", ord_date: new Date("2020-03-08"), price: 50, items: [ { sku: "oranges", qty: 10, price: 2.5 }, { sku: "pears", qty: 10, price: 2.5 } ], status: "A" }, { _id: 4, cust_id: "Busby Bee", ord_date: new Date("2020-03-18"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 5, cust_id: "Busby Bee", ord_date: new Date("2020-03-19"), price: 50, items: [ { sku: "chocolates", qty: 5, price: 10 } ], status: "A"}, { _id: 6, cust_id: "Cam Elot", ord_date: new Date("2020-03-19"), price: 35, items: [ { sku: "carrots", qty: 10, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" }, { _id: 7, cust_id: "Cam Elot", ord_date: new Date("2020-03-20"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 8, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 75, items: [ { sku: "chocolates", qty: 5, price: 10 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" }, { _id: 9, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 55, items: [ { sku: "carrots", qty: 5, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 }, { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 10, cust_id: "Don Quis", ord_date: new Date("2020-03-23"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" } ])
Retornar o preço total por cliente
Execute a operação map-reduce na collection orders para agrupar pelo cust_id e calcule a soma do price para cada cust_id:
Defina a função do mapa para processar cada documento de entrada:
Na função, o
thisrefere-se ao documento que a operação de redução de mapa está processando.A função mapeia o
pricepara ocust_idpara cada documento e emite ocust_ideprice.
var mapFunction1 = function() { emit(this.cust_id, this.price); }; Defina a função de redução correspondente com dois argumentos
keyCustIdevaluesPrices:O
valuesPricesé uma array cujos elementos são os valorespriceemitidos pela função de mapa e agrupados porkeyCustId.A função reduz a array
valuesPriceà soma de seus elementos.
var reduceFunction1 = function(keyCustId, valuesPrices) { return Array.sum(valuesPrices); }; Executar a redução de mapa em todos os documentos na coleção do
ordersutilizando a função de mapa domapFunction1e a função de redução doreduceFunction1:db.orders.mapReduce( mapFunction1, reduceFunction1, { out: "map_reduce_example" } ) Esta operação gera resultados para uma coleção denominada
map_reduce_example. Se a coleçãomap_reduce_examplejá existir, a operação substituirá o conteúdo pelos resultados desta operação de redução de mapa.Consulte a coleção
map_reduce_examplepara verificar os resultados:db.map_reduce_example.find().sort( { _id: 1 } ) A operação retorna estes documentos:
{ "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Busby Bee", "value" : 125 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Don Quis", "value" : 155 }
Alternativa de aggregation
Usando os operadores de aggregation pipeline disponíveis, você pode reescrever a operação de map-reduce sem definir funções personalizadas:
db.orders.aggregate([ { $group: { _id: "$cust_id", value: { $sum: "$price" } } }, { $out: "agg_alternative_1" } ])
O estágio
$groupagrupa pelocust_ide calcula o campovalue(consulte também$sum). O campovaluecontém o total depricepara cadacust_id.O estágio envia os seguintes documentos para o próximo estágio:
{ "_id" : "Don Quis", "value" : 155 } { "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Busby Bee", "value" : 125 } Em seguida, o
$outgrava a saída na coleçãoagg_alternative_1. Alternativamente, você pode utilizar$mergeao invés de$out.Consulte a coleção
agg_alternative_1para verificar os resultados:db.agg_alternative_1.find().sort( { _id: 1 } ) A operação retorna os seguintes documentos:
{ "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Busby Bee", "value" : 125 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Don Quis", "value" : 155 }
Dica
Para obter uma alternativa que usa expressões de agregação personalizadas, consulte Map-Reduce to Aggregation Pipeline Translation Examples.
Calcule o pedido e a quantidade total com a quantidade média por item
No exemplo seguinte, você visualizará uma operação de map-reduce na collection orders para todos os documentos que têm um valor ord_date maior ou igual a 2020-03-01.
A operação no exemplo:
Agrupa pelo campo
item.skue calcula o número de pedidos e a quantidade total solicitada para cadasku.Calcula a quantidade média por pedido para cada valor
skue mescla os resultados na coleta de saída.
Ao mesclar resultados, se um documento existente tiver a mesma chave que o novo resultado, a operação substituirá o documento existente. Se não houver nenhum documento existente com a mesma chave, a operação inserirá o documento.
Etapas de exemplo:
Defina a função do mapa para processar cada documento de entrada:
Na função, o
thisrefere-se ao documento que a operação de redução de mapa está processando.Para cada item, a função associa o
skua um novo objetovalueque contém ocountde1e o itemqtypara o pedido e emite osku(armazenado nokey) e ovalue.
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); } }; Defina a função de redução correspondente com dois argumentos
keySKUecountObjVals:countObjValsé uma matriz cujos elementos são os objetos mapeados para os valores agrupados dokeySKUpassados pela função de mapa para a função redutor.A função reduz a matriz
countObjValspara um único objetoreducedValueque contém os camposcounteqty.Em
reducedVal, o campocountcontém a soma dos camposcountdos elementos individuais da array e o campoqtycontém a soma dos camposqtydos elementos individuais da array.
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; }; Defina uma função de finalização com dois argumentos
keyereducedVal. A função modifica o objetoreducedValpara adicionar um campo calculado denominadoavge retorna o objeto modificado:var finalizeFunction2 = function (key, reducedVal) { reducedVal.avg = reducedVal.qty/reducedVal.count; return reducedVal; }; Execute a operação de redução de mapa na coleção do
ordersutilizando as funçõesmapFunction2,reduceFunction2efinalizeFunction2:db.orders.mapReduce( mapFunction2, reduceFunction2, { out: { merge: "map_reduce_example2" }, query: { ord_date: { $gte: new Date("2020-03-01") } }, finalize: finalizeFunction2 } ); Esta operação utiliza o campo
querypara selecionar apenas os documentos comord_datemaior ou igual anew Date("2020-03-01"). Em seguida, ele envia os resultados para uma coleçãomap_reduce_example2.Se a coleção
map_reduce_example2já existir, a operação fundirá o conteúdo existente com os resultados desta operação de redução de mapa. Ou seja, se um documento existente tiver a mesma chave que o novo resultado, a operação substituirá o documento existente. Se não houver nenhum documento existente com a mesma chave, a operação inserirá o documento.Consulte a coleção
map_reduce_example2para verificar os resultados:db.map_reduce_example2.find().sort( { _id: 1 } ) A operação retorna estes documentos:
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }
Alternativa de aggregation
Usando os operadores de aggregation pipeline disponíveis, você pode reescrever a operação de map-reduce sem definir funções personalizadas:
db.orders.aggregate( [ { $match: { ord_date: { $gte: new Date("2020-03-01") } } }, { $unwind: "$items" }, { $group: { _id: "$items.sku", qty: { $sum: "$items.qty" }, orders_ids: { $addToSet: "$_id" } } }, { $project: { value: { count: { $size: "$orders_ids" }, qty: "$qty", avg: { $divide: [ "$qty", { $size: "$orders_ids" } ] } } } }, { $merge: { into: "agg_alternative_3", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } } ] )
A etapa
$matchseleciona apenas os documentos comord_datemaior ou igual anew Date("2020-03-01").O estágio
$unwinddivide o documento pelo campo de arrayitemspara gerar um documento para cada elemento da array. Por exemplo:{ "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "apples", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "oranges", "qty" : 8, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "pears", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 4, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-18T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 5, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-19T00:00:00Z"), "price" : 50, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } ... Os
$groupgrupos de estágio peloitems.sku, calculando para cada sku:- O campo
qty. O campoqtycontém o - total
qtysolicitado por cadaitems.sku(consulte$sum).
- O campo
- A matriz
orders_ids. O campoorders_idscontém um - array de
_idde ordem distinta para oitems.sku(veja$addToSet).
- A matriz
{ "_id" : "chocolates", "qty" : 15, "orders_ids" : [ 2, 5, 8 ] } { "_id" : "oranges", "qty" : 63, "orders_ids" : [ 4, 7, 3, 2, 9, 1, 10 ] } { "_id" : "carrots", "qty" : 15, "orders_ids" : [ 6, 9 ] } { "_id" : "apples", "qty" : 35, "orders_ids" : [ 9, 8, 1, 6 ] } { "_id" : "pears", "qty" : 10, "orders_ids" : [ 3 ] } O estágio
$projectremodela o documento de saída para espelhar a saída do map-reduce para ter dois campos_idevalue. Os conjuntos$project:O estágio
$unwinddivide o documento pelo campo de arrayitemspara gerar um documento para cada elemento da array. Por exemplo:{ "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "apples", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "oranges", "qty" : 8, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "pears", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 4, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-18T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 5, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-19T00:00:00Z"), "price" : 50, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } ... Os
$groupgrupos de estágio peloitems.sku, calculando para cada sku:O campo
qty. O campoqtycontém o total deqtyordenados por cadaitems.skuutilizando$sum.A array
orders_ids. O campoorders_idscontém uma array de ordem distinta_idpara oitems.skuutilizando$addToSet.
{ "_id" : "chocolates", "qty" : 15, "orders_ids" : [ 2, 5, 8 ] } { "_id" : "oranges", "qty" : 63, "orders_ids" : [ 4, 7, 3, 2, 9, 1, 10 ] } { "_id" : "carrots", "qty" : 15, "orders_ids" : [ 6, 9 ] } { "_id" : "apples", "qty" : 35, "orders_ids" : [ 9, 8, 1, 6 ] } { "_id" : "pears", "qty" : 10, "orders_ids" : [ 3 ] } O estágio
$projectremodela o documento de saída para espelhar a saída do map-reduce para ter dois campos_idevalue. Os conjuntos$project:o
value.countpara o tamanho da arrayorders_idsusando$size.o
value.qtypara o campoqtydo documento de entrada.o
value.avgpara o número médio de quantidade por pedido usando$dividee$size.
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } Finalmente, o
$mergegrava a saída na coleçãoagg_alternative_3. Se um documento existente tiver a mesma chave_idque o novo resultado, a operação substituirá o documento existente. Se não houver nenhum documento existente com a mesma chave, a operação inserirá o documento.Consulte a coleção
agg_alternative_3para verificar os resultados:db.agg_alternative_3.find().sort( { _id: 1 } ) A operação retorna os seguintes documentos:
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }
Dica
Para obter uma alternativa que usa expressões de agregação personalizadas, consulte Map-Reduce to Aggregation Pipeline Translation Examples.
Para obter mais informações e exemplos, consulte a página Map-Reduce e Executar map-reduce incremental.
Saída
Se você definir o parâmetro out para gravar os resultados em uma coleção, o comando mapReduce retornará um documento no seguinte formato:
{ "result" : "map_reduce_example", "ok" : 1 }
Se você definir o parâmetro out para produzir os resultados in-line, o comando mapReduce retornará um documento no seguinte formato:
{ "results" : [ { "_id" : <key>, "value" :<reduced or finalizedValue for key> }, ... ], "ok" : <int> }
mapReduce.resultsPara saída escrita in-line, um array de documentos resultantes. Cada documento resultante contém dois campos:
_ido campo contém o valorkey,valueo campo contém o valor reduzido ou finalizado para akeyassociada.
mapReduce.okO valor
1indica que o comandomapReducefoi executado com sucesso. O valor0indica um erro.
Além dos campos de retorno específicos do comando mencionados anteriormente, db.runCommand() inclui informações adicionais:
para conjuntos de réplicas:
$clusterTimeeoperationTime.para clusters fragmentados:
operationTimee$clusterTime.
Consulte Resposta db.runCommand para obter detalhes sobre esses campos.