Para agentes de IA: um índice de documentação está disponível em https://www.mongodb.com/pt-br/docs/llms.txt — as versões de markdown de todas as páginas estão disponíveis anexando .md a qualquer caminho de URL.

$ acumulador ( operador acumulador )

$accumulator

Importante

JavaScript do lado do servidor obsoleto

A partir do MongoDB 8.0, as funções JavaScript no lado do servidor ($accumulator, $function, $where) são descontinuados. O MongoDB registra um aviso quando você executa essas funções.

Define um operador acumulador personalizado. Os acumuladores são operadores que mantêm seu estado (por exemplo, totais, máximos, mínimos e dados relacionados) à medida que os documentos avançam no pipeline. Use o operador $accumulator para executar suas próprias funções JavaScript para implementar um comportamento não suportado pela linguagem de query MongoDB. Consulte também $function.

$accumulator está disponível nestes estágios:

Importante

Executar JavaScript dentro de um operador de agregação pode diminuir o desempenho. Use o operador $accumulator somente se os operadores de pipeline fornecidos não puderem atender às necessidades do seu aplicativo.

O operador $accumulator tem esta sintaxe:

{ $accumulator: { init: <code>, initArgs: <array expression>, // Optional accumulate: <code>, accumulateArgs: <array expression>, merge: <code>, finalize: <code>, // Optional lang: <string> }}
Campo
Tipo
Descrição

String ou código

Função usada para inicializar o estado. A função init recebe seus argumentos da expressão de array initArgs. Você pode especificar a definição da função como tipos de BSON ou String do tipo BSON.

A função init tem a seguinte forma:

function (<initArg1>, <initArg2>, ...) { ... return <initialState>}

O derramamento no disco ou a execução de uma query em um cluster fragmentado pode fazer com que o acumulador seja computado como uma mescla de vários subacumuladores, cada um dos quais começa chamando init(). Certifique-se de que suas funções init(), accumulate() e merge() sejam compatíveis com este modelo de execução.

Array

Opcional. Argumentos passados para a função init.

initArgs tem o seguinte formato:

[ <initArg1>, <initArg2>, ... ]

IMPORTANTE: Quando usado em um estágio $bucketAuto, initArgs não pode referir-se à chave do grupo (ou seja, você não pode usar a sintaxe $<fieldName>). Em vez disso, em um estágio do $bucketAuto, você pode somente especificar valores constantes no initArgs.

String ou código

Função usada para acumular documentos. A função accumulate recebe seus argumentos do estado atual e da expressão da array accumulateArgs. O resultado da função accumulate torna-se o novo estado. Você pode especificar a definição da função como Code ou String do tipo BSON.

A função accumulate tem a seguinte forma:

function(state, <accumArg1>, <accumArg2>, ...) { ... return <newState>}

Array

Argumentos passados para a função accumulate. Você pode usar accumulateArgs para especificar quais valores de campo passar para a função accumulate.

accumulateArgs tem o seguinte formato:

[ <accumArg1>, <accumArg2>, ... ]

String ou código

Função usada para mesclar dois estados internos. merge deve ser do tipo String ou Code de BSON. merge retorna o resultado combinado dos dois estados mesclados. Para obter informações sobre quando a função de mesclagem é chamada, consulte Mesclar dois estados com $merge.

A função merge tem a seguinte forma:

function (<state1>, <state2>) { <logic to merge state1 and state2> return <newState>}

String ou código

Opcional. Função usada para atualizar o resultado do acúmulo.

A função finalize tem a seguinte forma:

function (state) { ... return <finalState>}

String

A linguagem usada no código $accumulator.

IMPORTANTE: Atualmente, o único valor suportado para lang é js.

As etapas a seguir descrevem como o operador $accumulator processa documentos:

  1. O operador começa em um estado inicial, definido pela função init.

  2. Para cada documento, o operador atualiza o estado com base na função accumulate . O primeiro argumento da função accumulate é o estado atual, e os argumentos adicionais são especificados na array accumulateArgs.

  3. Quando o operador precisa mesclar vários estados intermediários, ele executa a função de mesclagem . Para obter mais informações sobre quando a função de mesclagem é chamada, consulte Mesclar dois estados com $merge.

  4. Se uma função finalizar tiver sido definida, uma vez que todos os documentos tenham sido processados e o estado tenha sido atualizado de acordo, finalizar converte o estado em uma saída final.

Como parte de suas operações internas, o operador $accumulator pode precisar mesclar dois estados intermediários separados. A função merge especifica como o operador deve mesclar dois estados.

A função de mesclagem sempre mescla dois estados de cada vez. Se mais de dois estados precisarem ser mesclados, a fusão resultante de dois estados será mesclada com um único estado. Esse processo se repete até que todos os estados sejam mesclados.

Por exemplo, $accumulator pode precisar combinar dois estados nos seguintes cenários:

  • $accumulator é executado em um cluster fragmentado. O operador precisa mesclar os resultados de cada fragmento para obter o resultado final.

  • Uma única operação $accumulator excede seu limite de memória especificado. Se você especificar a opção allowDiskUse, o operador armazenará a operação em andamento no disco e finalizará a operação na memória. Quando a operação for concluída, os resultados do disco e da memória serão mesclados usando a função de mesclagem .

A ordem em que o MongoDB processa documentos para as funções init(), accumulate() e merge() pode variar e ser diferente da ordem em que esses documentos são especificados para a função $accumulator.

Por exemplo, considere uma série de documentos em que os campos _id são as letras do alfabeto:

{ _id: 'a' },{ _id: 'b' },{ _id: 'c' }...{ _id: 'z' }

Em seguida, considere um pipeline de agregação que classifica os documentos pelo campo _id e usa uma função $accumulator para concatenar os valores do campo _id:

[ { $sort: { _id: 1 } }, { $group: { _id: null, alphabet: { $accumulator: { init: function() { return "" }, accumulate: function(state, letter) { return(state + letter) }, accumulateArgs: [ "$_id" ], merge: function(state1, state2) { return(state1 + state2) }, lang: "js" } } } }]

O MongoDB não garante que os documentos sejam processados na ordem de classificação, o que significa que o campo alphabet não é necessariamente definido como abc...z.

Devido a esse comportamento, garanta que sua função $accumulator não precise processar e retornar documentos em uma ordem específica.

Para usar $accumulator, os scripts do lado do servidor devem estar habilitados.

Se você não usar $accumulator (ou $function, $where ou mapReduce), desative o script do lado do servidor:

Consulte também ➤ Executar o MongoDB com opções de configuração seguras.

O MongoDB 6.0 atualiza o mecanismo JavaScript interno usado para expressões JavaScript do lado do servidor, $accumulator, $function e $where e de MozJS-60 para MozJS-91. Várias funções de array e string obsoletas e não padrão que existiam no MozJS-60 foram removidas no MozJS-91.

Os exemplos nesta página usam dados do conjunto de dados sample_mflix. Para obter detalhes sobre como carregar este conjunto de dados em sua implantação do MongoDB autogerenciado, consulte Carregar o conjunto de dados de amostra. Se você fez alguma modificação nos bancos de dados de amostra, talvez seja necessário descartar e recriar os bancos de dados para executar os exemplos nesta página.

Observação

Este exemplo mostra como usar o operador $accumulator para implementar o operador $avg, que já é suportado pelo MongoDB. O objetivo deste exemplo não é implementar novas funcionalidades, mas ilustrar o comportamento e sintaxe do operador $accumulator com uma lógica familiar.

A operação a seguir groups os documentos por rated e usa $accumulator para calcular a média de imdb.rating para cada classificação de conteúdo. O estágio $match restringe a entrada às classificações de conteúdo G, PG, PG-13 e R e exclui documentos em que imdb.rating não é duplo, como uma string vazia:

db.movies.aggregate( [ { $match: { rated: { $in: [ "G", "PG", "PG-13", "R" ] }, "imdb.rating": { $type: "double" } } }, { $group: { _id: "$rated", avgRating: { $accumulator: { init: function() { // Set the initial state return { count: 0, sum: 0 } }, accumulate: function(state, rating) { // Define how to update the state return { count: state.count + 1, sum: state.sum + rating } }, accumulateArgs: [ "$imdb.rating" ], // Argument required by the accumulate function merge: function(state1, state2) { // When the operator performs a merge, return { // add the fields from the two states count: state1.count + state2.count, sum: state1.sum + state2.sum } }, finalize: function(state) { // After collecting the results from all documents, return (state.sum / state.count) // calculate the average }, lang: "js" } } } }, { $sort: { _id: 1 } }] )
[ { _id: 'G', avgRating: 6.628092243186578 }, { _id: 'PG', avgRating: 6.43525917926564 }, { _id: 'PG-13', avgRating: 6.404911676001717 }, { _id: 'R', avgRating: 6.456657633242984 }]

O $accumulator define um estado inicial onde count e sum estão ambos configurados para 0. Para cada documento que o $accumulator processa, ele atualiza o estado da seguinte forma:

  • Incrementando o count por 1 e

  • Adicionando os valores do campo imdb.rating do documento ao sum. A função accumulate pode acessar o campo imdb.rating porque ele é passado no campo AccumulateArgs.

Com cada documento processado, a função de acumulação retorna o estado atualizado.

Depois que todos os documentos tiverem sido processados, a função finalizar divide o sum das classificações pelo count dos documentos para obter a média. Isso remove a necessidade de manter uma média computada em execução, pois a função finalizar recebe o sum cumulativo e o count de todos os documentos.

Esta operação é equivalente à seguinte pipeline, que utiliza o operador $avg:

db.movies.aggregate( [ { $match: { rated: { $in: [ "G", "PG", "PG-13", "R" ] }, "imdb.rating": { $type: "double" } } }, { $group: { _id: "$rated", avgRating: { $avg: "$imdb.rating" } } }, { $sort: { _id: 1 } }] )
[ { _id: 'G', avgRating: 6.6280922431865825 }, { _id: 'PG', avgRating: 6.435259179265659 }, { _id: 'PG-13', avgRating: 6.404911676001723 }, { _id: 'R', avgRating: 6.456657633242999 }]

Você pode utilizar a opção initArgs para variar o estado inicial de $accumulator. Isso pode ser útil se você quiser, por exemplo:

  • Usar o valor de um campo que não está em seu estado para afetar seu estado, ou

  • Definir o estado inicial para um valor diferente com base no grupo que está sendo processado.

Suponha que um aplicação permita que os usuários consultem esses dados para encontrar filmes. Pode ser útil mostrar mais resultados para a classificação de conteúdo que o usuário prefere. Para este exemplo, a classificação do conteúdo preferencial do usuário é PG-13, que é passada para a função init como userProfileRated.

O seguinte pipeline de agregação groups os documentos por rated. A operação utiliza o $accumulator para exibir um número diferente de filmes de cada classificação de conteúdo, dependendo se a classificação do filme corresponde à classificação no perfil do usuário:

Observação

Para executar esse exemplo com uma classificação de conteúdo preferencial diferente, substitua "PG-13" na array initArgs por outro valor, como "R".

db.movies.aggregate( [ { $match: { rated: { $in: [ "G", "PG", "PG-13", "R" ] }, "imdb.rating": { $type: "double" } } }, { $sort: { "imdb.rating": -1, title: 1 } }, { $group: { _id: { rated: "$rated" }, movies: { $accumulator: { init: function(rated, userProfileRated) { // Set the initial state return { max: rated === userProfileRated ? 3 : 1, // If the group matches the user's rating, movies: [] // return 3 movies. Otherwise, return 1. } }, initArgs: [ "$rated", "PG-13" ], // Argument to pass to the init function accumulate: function(state, movieTitle) { // Define how to update the state if (state.movies.length < state.max) { state.movies.push(movieTitle); } return state; }, accumulateArgs: [ "$title" ], // Argument required by the accumulate function merge: function(state1, state2) { return { max: state1.max, movies: state1.movies.concat(state2.movies).slice(0, state1.max) } }, finalize: function(state) { // Adjust the state to only return the field we need return state.movies }, lang: "js" } } } }, { $sort: { "_id.rated": 1 } }] )
[ { _id: { rated: 'G' }, movies: [ 'Modern Times' ] }, { _id: { rated: 'PG' }, movies: [ 'Life' ] }, { _id: { rated: 'PG-13' }, movies: [ 'A Brave Heart: The Lizzie Velasquez Story', 'The Dark Knight', 'The Lord of the Rings: The Return of the King' ] }, { _id: { rated: 'R' }, movies: [ 'The Shawshank Redemption' ] }]

A função init define um estado inicial que contém os campos max e movies. O campo max define o número máximo de filmes para este grupo em particular. Se o campo rated do documento corresponder a userProfileRated, esse grupo conterá um máximo de 3 filmes. Caso contrário, se o campo rated do documento não corresponder a userProfileRated, o grupo conterá no máximo um único filme. A função init recebe os argumentos rated e userProfileRated da arrayinitArgs.

Para cada documento que o $accumulator processa, ele empurra o title do filme para a array movies, se esse título não colocar o comprimento de movies sobre o valor max. Com cada documento processado, a função de acumular retorna o estado atualizado.

A função Mesclar define como mesclar dois estados. A função concatena juntos os arrays de movies de cada estado, e o comprimento do array resultante é limitado usando o método slice() para garantir que ele não exceda o valor max.

Depois que todos os documentos forem processados, a função finalizar modifica o estado resultante para retornar apenas os títulos dos filmes. Sem essa função, o campo max também seria incluído na saída, o que não atende a nenhuma necessidade do aplicação.