Redução de mapa
Nesta página
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
,$merge
e outros.Nas operações de map-reduce que exigem funcionalidade personalizada, você pode usar os operadores de agregação
$accumulator
e$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
mapReduce
O comando
mapReduce
permite a você executar operações de aggregation de map-reduce em uma collection.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 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. | |||||||||||
| 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 comothis
dentro da função.A função
map
não deve acessar o banco de dados por nenhum motivo.A função
map
deve ser pura ou não impacto fora dela (ou seja, efeitos colaterais).A função
map
pode, opcionalmente, chamaremit(key,value)
várias vezes para criar um documento de saída associandokey
avalue
.
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
reduce
não deve acessar o banco de dados, mesmo para realizar operações de leitura.A função
reduce
não deve afetar o sistema externo.O MongoDB pode invocar a função
reduce
mais de uma vez para a mesma chave. Neste caso, a saída anterior da funçãoreduce
para esta chave se tornará um dos valores de entrada para a próxima invocação da funçãoreduce
para esta chave.A função
reduce
pode acessar as variáveis definidas no parâmetroscope
.As entradas para
reduce
nã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 emreduce
etapas 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
value
emitido pela funçãomap
.a função
reduce
deve ser associativa. A seguinte declaração deve ser verdadeira:reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] ) a função
reduce
deve ser idempotente. Confirme se a afirmação a seguir é verdadeira:reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray ) a função
reduce
deve ser comutativa, isto é, a ordem dos elementos novaluesArray
nã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
finalize
não deve acessar o banco de dados por nenhum motivo.A função
finalize
deve ser pura ou não impacto fora dela (ou seja, efeitos colaterais).A função
finalize
pode 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:replace
Substitua o conteúdo de
<collectionName>
se a collection com<collectionName>
existir.merge
Mescle 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.
reduce
Mescle 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
reduce
aos 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
this
refere-se ao documento que a operação de redução de mapa está processando.A função mapeia o
price
para ocust_id
para cada documento e emite ocust_id
eprice
.
var mapFunction1 = function() { emit(this.cust_id, this.price); }; Defina a função de redução correspondente com dois argumentos
keyCustId
evaluesPrices
:O
valuesPrices
é uma array cujos elementos são os valoresprice
emitidos 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
orders
utilizando a função de mapa domapFunction1
e 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_example
já existir, a operação substituirá o conteúdo pelos resultados desta operação de redução de mapa.Consulte a coleção
map_reduce_example
para 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
$group
agrupa pelocust_id
e calcula o campovalue
(consulte também$sum
). O campovalue
contém o total deprice
para 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
$out
grava a saída na coleçãoagg_alternative_1
. Alternativamente, você pode utilizar$merge
ao invés de$out
.Consulte a coleção
agg_alternative_1
para 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
Veja também:
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.sku
e calcula o número de pedidos e a quantidade total solicitada para cadasku
.Calcula a quantidade média por pedido para cada valor
sku
e 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
this
refere-se ao documento que a operação de redução de mapa está processando.Para cada item, a função associa o
sku
a um novo objetovalue
que contém ocount
de1
e o itemqty
para 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
keySKU
ecountObjVals
:countObjVals
é uma matriz cujos elementos são os objetos mapeados para os valores agrupados dokeySKU
passados pela função de mapa para a função redutor.A função reduz a matriz
countObjVals
para um único objetoreducedValue
que contém os camposcount
eqty
.Em
reducedVal
, o campocount
contém a soma dos camposcount
dos elementos individuais da array e o campoqty
contém a soma dos camposqty
dos 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
key
ereducedVal
. A função modifica o objetoreducedVal
para adicionar um campo calculado denominadoavg
e 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
orders
utilizando as funçõesmapFunction2
,reduceFunction2
efinalizeFunction2
: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
query
para selecionar apenas os documentos comord_date
maior 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_example2
já 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_example2
para 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
$match
seleciona apenas os documentos comord_date
maior ou igual anew Date("2020-03-01")
.O estágio
$unwind
divide o documento pelo campo de arrayitems
para 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
$group
grupos de estágio peloitems.sku
, calculando para cada sku:- O campo
qty
. O campoqty
contém o - total
qty
solicitado por cadaitems.sku
(consulte$sum
).
- O campo
- A matriz
orders_ids
. O campoorders_ids
contém um - array de
_id
de 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
$project
remodela o documento de saída para espelhar a saída do map-reduce para ter dois campos_id
evalue
. Os conjuntos$project
:O estágio
$unwind
divide o documento pelo campo de arrayitems
para 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
$group
grupos de estágio peloitems.sku
, calculando para cada sku:O campo
qty
. O campoqty
contém o total deqty
ordenados por cadaitems.sku
utilizando$sum
.A array
orders_ids
. O campoorders_ids
contém uma array de ordem distinta_id
para oitems.sku
utilizando$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
$project
remodela o documento de saída para espelhar a saída do map-reduce para ter dois campos_id
evalue
. Os conjuntos$project
:o
value.count
para o tamanho da arrayorders_ids
usando$size
.o
value.qty
para o campoqty
do documento de entrada.o
value.avg
para o número médio de quantidade por pedido usando$divide
e$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
$merge
grava a saída na coleçãoagg_alternative_3
. Se um documento existente tiver a mesma chave_id
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
agg_alternative_3
para 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
Veja também:
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.results
Para saída escrita in-line, um array de documentos resultantes. Cada documento resultante contém dois campos:
_id
o campo contém o valorkey
,value
o campo contém o valor reduzido ou finalizado para akey
associada.
mapReduce.ok
O valor
1
indica que o comandomapReduce
foi executado com sucesso. O valor0
indica 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:
$clusterTime
eoperationTime
.para clusters fragmentados:
operationTime
e$clusterTime
.
Consulte Resposta db.runCommand para obter detalhes sobre esses campos.