Menu Docs
Página inicial do Docs
/
Manual do MongoDB
/ / /

Redução de mapa

Nesta página

  • Definição
  • Compatibilidade
  • Sintaxe
  • Campos de comando
  • Uso
  • Acesso necessário
  • Restrições
  • Exemplos de map-reduce
  • Saída
  • Informações adicionais

Observação

Pipeline de Agregação como Alternativa à Redução de Mapa

A partir do MongoDB , 5.0, map-reduce está obsoleto:

Para obter exemplos de alternativas de aggregation pipeline para map-reduce, consulte:

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 auxiliar mapReduce().

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.

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

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>
}
)

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 query antes de ser processada pela função map.

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 value a uma key e emite a key e o valor pair. Você pode especificar a função como Javascript do tipo BSON (BSON tipo 13) ou string (BSON tipo 2).

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 values associados a uma determinada key. Você pode especificar a função como JavaScript do tipo BSON (BSON tipo 13) ou string (BSON tipo 2).

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 map.

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 map.

Javascript ou string

Opcional. Uma função JavaScript que modifica a saída após a função reduce. Você pode especificar a função como JavaScript do tipo BSON (BSON tipo 13) ou string (BSON tipo 2).

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 map, reduce e finalize .

booleano

Opcional. Especifica se serão convertidos dados intermediários em formato BSON entre a execução das funções map e reduce.

Padrão é false.

Se false:

  • Internamente, o MongoDB converte os objetos JavaScript emitidos pela função map em objetos BSON. Em seguida, esses objetos BSON são convertidos de volta para objetos JavaScript ao chamar a função reduce.

  • A operação map-reduce posiciona os objetos BSON intermediários em armazenamento temporário no disco. Isto permite que a operação map-reduce seja executada em conjuntos de dados arbitrariamente grandes.

Se true:

  • Internamente, os objetos JavaScript emitidos durante a função map permanecem como objetos JavaScript. Não há necessidade de converter os objetos para a função reduce, o que pode resultar em execução mais rápida.

  • Você só pode usar jsMode para conjuntos de resultados com menos de 500.000 argumentos key distintos para a função emit() do mapeador.

booleano

Opcional. Especifica se as informações de timing devem ser incluídas nas informações do resultado. Defina verbose como true para incluir as informações de timing .

Padrão é false.

Esta opção é ignorada. As informações do resultado sempre excluem as informações de timing . Você pode visualizar informações de tempo executando explain com o mapReduce comando "executionStats" nos "allPlansExecution" verbosity modos ou.

booleano

Opcional. Habilita o mapReduce para ignorar a validação do documento durante a operação. Isso permite inserir documentos que não atendam aos requisitos de validação.

Se a opção de saída estiver definida inline como, não ocorrerá validação do documento . Se a saída for para uma collection, mapReduce observa todas as regras de validação que a collection tem e não insere nenhum documento inválido, a menos que o bypassDocumentValidation parâmetro seja definido como true.

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:

collation: {
locale: <string>,
caseLevel: <boolean>,
caseFirst: <string>,
strength: <int>,
numericOrdering: <boolean>,
alternate: <string>,
maxVariable: <string>,
backwards: <boolean>
}

Ao especificar agrupamento, o campo locale é obrigatório; todos os outros campos de agrupamento são opcionais. Para obter descrições dos campos, consulte Documento de agrupamento.

Se o agrupamento não for especificado, mas a coleção tiver um agrupamento padrão (consulte db.createCollection()), a operação usará o agrupamento especificado para a coleção.

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.

maxTimeMS

non-negative integer

Opcional.

Especifica um limite de tempo em milissegundos. Se você não especificar um valor para maxTimeMS, as operações não atingirão o tempo limite. Um valor 0 especifica explicitamente o comportamento ilimitado padrão.

O MongoDB encerra as operações que excedem o limite de tempo alocado usando o mesmo mecanismo de db.killOp(). O MongoDB só encerra uma operação em um de seus pontos de interrupção designados.

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.

comment

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).

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.

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 como this 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, chamar emit(key,value) várias vezes para criar um documento de saída associando key a value.

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); });
}

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ção reduce para esta chave se tornará um dos valores de entrada para a próxima invocação da função reduce para esta chave.

  • A função reduce pode acessar as variáveis definidas no parâmetro scope.

  • 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 em reduce 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ção map.

  • 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 no valuesArray não deve afetar a saída da função reduce, de forma que a seguinte declaração seja verdadeira:

    reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )

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âmetro scope.

Você pode especificar as seguintes opções para o parâmetro out:

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>

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.

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.

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.

O comando mapReduce não mais compatível com afterClusterTime. Então, mapReduce não pode ser associada a sessões causalmente consistentes.

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" }
])

Execute a operação map-reduce na collection orders para agrupar pelo cust_id e calcule a soma do price para cada cust_id:

  1. 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 o cust_id para cada documento e emite o cust_id e price.

    var mapFunction1 = function() {
    emit(this.cust_id, this.price);
    };
  2. Defina a função de redução correspondente com dois argumentos keyCustId e valuesPrices:

    • O valuesPrices é uma array cujos elementos são os valores price emitidos pela função de mapa e agrupados por keyCustId.

    • A função reduz a array valuesPrice à soma de seus elementos.

    var reduceFunction1 = function(keyCustId, valuesPrices) {
    return Array.sum(valuesPrices);
    };
  3. Executar a redução de mapa em todos os documentos na coleção do orders utilizando a função de mapa do mapFunction1 e a função de redução do reduceFunction1 :

    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ção map_reduce_example já existir, a operação substituirá o conteúdo pelos resultados desta operação de redução de mapa.

  4. 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 }

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" }
])
  1. O estágio $group agrupa pelo cust_id e calcula o campo value (consulte também $sum). O campo value contém o total de price para cada cust_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 }
  2. Em seguida, o $out grava a saída na coleção agg_alternative_1. Alternativamente, você pode utilizar $merge ao invés de $out.

  3. 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.

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:

  1. Agrupa pelo campo item.sku e calcula o número de pedidos e a quantidade total solicitada para cada sku.

  2. 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:

  1. 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 objeto value que contém o count de 1 e o item qty para o pedido e emite o sku (armazenado no key) e o value.

    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);
    }
    };
  2. Defina a função de redução correspondente com dois argumentos keySKU e countObjVals:

    • countObjVals é uma matriz cujos elementos são os objetos mapeados para os valores agrupados do keySKU passados pela função de mapa para a função redutor.

    • A função reduz a matriz countObjVals para um único objeto reducedValue que contém os campos count e qty.

    • Em reducedVal, o campo count contém a soma dos campos count dos elementos individuais da array e o campo qty contém a soma dos campos qty 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;
    };
  3. Defina uma função de finalização com dois argumentos key e reducedVal. A função modifica o objeto reducedVal para adicionar um campo calculado denominado avg e retorna o objeto modificado:

    var finalizeFunction2 = function (key, reducedVal) {
    reducedVal.avg = reducedVal.qty/reducedVal.count;
    return reducedVal;
    };
  4. Execute a operação de redução de mapa na coleção do orders utilizando as funções mapFunction2, reduceFunction2 e finalizeFunction2:

    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 com ord_date maior ou igual a new Date("2020-03-01"). Em seguida, ele envia os resultados para uma coleção map_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.

  5. 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 } }

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" } }
] )
  1. A etapa $match seleciona apenas os documentos com ord_date maior ou igual a new Date("2020-03-01").

  2. O estágio $unwind divide o documento pelo campo de array items 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" }
    ...
  3. Os $group grupos de estágio pelo items.sku, calculando para cada sku:

    • O campo qty. O campo qty contém o
      total qty solicitado por cada items.sku (consulte $sum).
    • A matriz orders_ids. O campo orders_ids contém um
      array de _id de ordem distinta para o items.sku (veja $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 ] }
  4. O estágio $project remodela o documento de saída para espelhar a saída do map-reduce para ter dois campos _id e value. Os conjuntos $project :

  5. O estágio $unwind divide o documento pelo campo de array items 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" }
    ...
  6. Os $group grupos de estágio pelo items.sku, calculando para cada sku:

    • O campo qty. O campo qty contém o total de qty ordenados por cada items.sku utilizando $sum.

    • A array orders_ids. O campo orders_ids contém uma array de ordem distinta _id para o items.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 ] }
  7. O estágio $project remodela o documento de saída para espelhar a saída do map-reduce para ter dois campos _id e value. Os conjuntos $project :

    • o value.count para o tamanho da array orders_ids usando $size.

    • o value.qty para o campo qty 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 } }
  8. Finalmente, o $merge grava a saída na coleção agg_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.

  9. 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.

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.result

Para saída enviada para uma collection, esse valor é:

  • uma string para o nome da coleção se out não especificou o nome do banco de dados, ou

  • um documento com os campos db e collection se out especificou um nome de banco de dados e de coleção.

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 valor key,

  • value o campo contém o valor reduzido ou finalizado para a key associada.

mapReduce.ok

O valor 1 indica que o comando mapReduce foi executado com sucesso. O valor 0 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 e operationTime.

  • para clusters fragmentados: operationTime e $clusterTime.

Consulte Resposta db.runCommand para obter detalhes sobre esses campos.

Voltar

distinto