Definição
$groupA etapa $group combina múltiplos documentos que possuem os mesmos campos, campo ou expressão em um único documento, conforme uma chave de agrupamento. O resultado é um documento por chave de grupo exclusiva.
Uma chave de grupo geralmente é um campo ou grupo de campos. A chave do grupo também pode ser o resultado de uma expressão. Use o campo
_idno estágio de pipeline$grouppara definir a chave do grupo. Veja abaixo exemplos de uso.Na saída do estágio
$group, o campo_idé definido como a chave de grupo desse documento.Os documentos de saída também podem conter campos adicionais que são definidos usando expressions acumuladoras.
Observação
$groupnão ordena seus documentos de saída.
Compatibilidade
Você pode utilizar o $group para implantações hospedadas nos seguintes ambientes:
MongoDB Atlas: o serviço totalmente gerenciado para implantações do MongoDB na nuvem
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
O estágio $group tem a seguinte forma de protótipo:
{ $group: { _id: <expression>, // Group key <field1>: { <accumulator1> : <expression1> }, ... } }
Campo | Descrição |
|---|---|
| Obrigatório. A expressão |
| Opcional. Computado usando os operadores acumulador . |
O _id e os operadores acumuladores podem aceitar qualquer expression válido. Para mais informações sobre expressões, consulte Expressões.
Considerações
Desempenho
$group é um estágio de bloqueio, que faz com que o pipeline espere que todos os dados de entrada sejam recuperados para o estágio de bloqueio antes de processar os dados. Um estágio de bloqueio pode reduzir o desempenho porque reduz o processamento paralelo de um pipeline com vários estágios. Um estágio de bloqueio também pode usar quantidades substanciais de memória para grandes conjuntos de dados.
Operador acumulador
O operador <accumulator> deve ser um dos seguintes operadores acumuladores:
Nome | Descrição |
|---|---|
Retorna o resultado de uma função de acumulador definida pelo usuário. | |
Retorna uma array de valores de expressão exclusivos para cada grupo. A ordem dos elementos da array é indefinida. Alterado na versão 5.0: Disponível no estágio | |
Retorna uma média de valores numéricos. Ignora valores não numéricos. Alterado na versão 5.0: Disponível no estágio | |
Retorna o elemento inferior de um grupo de acordo com a ordem de classificação especificada. Novidades na versão 5.2. Disponível nos estágios | |
Retorna uma agregação dos campos Novidades na versão 5.2. Disponível nos estágios | |
Retorna o número de documentos em um grupo. Diferente do estágio Novidade na versão 5.0: Disponível nos estágios | |
Retorna o resultado de uma expressão para o primeiro documento em um grupo. Alterado na versão 5.0: Disponível no estágio | |
Retorna uma agregação dos primeiros Novidade na versão 5.2: Disponível nos estágios | |
Retorna o resultado de uma expressão para o último documento em um grupo. Alterado na versão 5.0: Disponível no estágio | |
Retorna uma agregação dos últimos Novidade na versão 5.2: Disponível nos estágios | |
Retorna o valor de expressão mais alto para cada grupo. Alterado na versão 5.0: Disponível no estágio | |
Retorna uma agregação dos Novidades na versão 5.2. Disponível em | |
Retorna uma aproximação da mediana, o 50º percentil, como um valor escalar. Novidades na versão 7.0. Este operador está disponível como acumulador nestas etapas: Também está disponível como uma expressão de agregação. | |
Retorna um documento criado combinando os documentos de entrada de cada grupo. | |
Retorna o valor de expressão mais baixo para cada grupo. Alterado na versão 5.0: Disponível no estágio | |
Retorna uma agregação dos Novidades na versão 5.2. Disponível em | |
Retorna uma array de valores escalares que correspondem aos valores percentuais especificados. Novidades na versão 7.0. Este operador está disponível como acumulador nestas etapas: Também está disponível como uma expressão de agregação. | |
Retorna uma matriz de valores de expressão para documentos em cada grupo. Alterado na versão 5.0: Disponível no estágio | |
Retorna o desvio padrão da população dos valores de entrada. Alterado na versão 5.0: Disponível no estágio | |
Retorna o desvio padrão da amostra dos valores de entrada. Alterado na versão 5.0: Disponível no estágio | |
Retorna uma soma de valores numéricos. Ignora valores não numéricos. Alterado na versão 5.0: Disponível no estágio | |
Retorna o principal elemento de um grupo de acordo com a ordem de classificação especificada. Novidades na versão 5.2. Disponível nos estágios | |
Retorna uma agregação dos principais campos Novidades na versão 5.2. Disponível nos estágios |
$group e restrições de memória
Se o estágio $group exceder 100 megabytes de RAM, o MongoDB gravará os dados em arquivos temporários. No entanto, se a opção allowDiskUse estiver definida como false, $group retornará um erro. Para obter mais informações, consulte Limites do pipeline de agregação.
$group Otimizações de desempenho
Esta seção descreve otimizações para melhorar o desempenho de $group. Existem otimizações que você pode fazer manualmente e otimizações que o MongoDB faz internamente.
Otimização para retornar o primeiro ou último documento de cada grupo
Se um pipeline sorts e groups pelo mesmo campo e o estágio $group utilizar somente o operador acumulador $first ou $last, considere adicionar um índice no campo agrupado que corresponda à ordem de classificação. Em alguns casos, o estágio $group pode usar o índice para localizar rapidamente o primeiro ou último documento de cada grupo.
Exemplo
Se a coleção movies contiver um índice { year: 1, title: 1 }, o pipeline a seguir poderá usar esse índice para localizar o primeiro documento de cada grupo:
db.movies.aggregate([ { $sort: { year: 1, title: 1 } }, { $group: { _id: { year: "$year" }, title: { $first: "$title" } } } ])
Mecanismo de execução de consulta baseado em slot
A partir da versão 5.2, O MongoDB utiliza o mecanismo de consulta de execução baseado em slot para executar estágios $group se:
$groupé o primeiro estágio do pipeline.Todos os estágios anteriores do pipeline também podem ser executados pelo mecanismo de execução baseado em slot.
Para mais informações, consulte Otimização do$group.
Exemplos
Contagem do número de documentos em uma coleção
Os exemplos nesta página utilizam dados do conjunto de dados de amostra sample_mflix. Para obter detalhes sobre como carregar esse conjunto de dados em sua implantação autogerenciada do MongoDB , consulte Carregar o conjunto de dados de amostra. Se você fez modificações nos bancos de dados de amostra, talvez seja necessário descartar e recriar os bancos de dados para executar os exemplos nesta página.
A operação de agregação a seguir usa o estágio $group para contar o número de documentos na coleção movies:
db.movies.aggregate([ { $group: { _id: null, count: { $count: {} } } } ])
[ { _id: null, count: 21349 } ]
Esta operação de agregação é equivalente à seguinte declaração SQL:
SELECT COUNT(*) AS count FROM movies
Retrieve Distinct Values
A seguinte operação de agregação utiliza o estágio para recuperar $group os rated valores distintos da movies coleção:
db.movies.aggregate( [ { $group : { _id : "$rated" } } ] )
[ { _id: 'TV-PG' }, { _id: 'PG' }, { _id: 'TV-14' }, { _id: 'OPEN' }, { _id: 'Not Rated' }, { _id: 'GP' }, { _id: 'TV-Y7' }, { _id: 'G' }, { _id: 'PG-13' }, { _id: null }, { _id: 'M' }, { _id: 'R' }, { _id: 'TV-MA' }, { _id: 'APPROVED' }, { _id: 'PASSED' }, { _id: 'Approved' }, { _id: 'AO' }, { _id: 'TV-G' } ]
Observação
Quando você utiliza $group para recuperar valores distintos em uma coleção fragmentada, se a operação resultar em DISTINCT_SCAN um, o resultado poderá conter documentos órfãos.
O único pipeline semanticamente correto afetado é efetivamente o equivalente lógico de um comando, em que há distinct um $group estágio no início do pipeline ou próximo a ele e o $group não é precedido por um estágio $sort .
Por exemplo, operações $group do seguinte formulário podem resultar em um DISTINCT_SCAN:
{ $group : { _id : "$<field>" } }
Para obter mais informações sobre o comportamento de recuperar valores distintos, consulte o comportamento de comando distinto.
Para ver se a sua operação resulta em um,DISTINCT_SCAN verifique os resultados de explicação da sua operação.
Agrupar por classificação
A seguinte operação de agregação agrupa documentos pelo campo rated , calculando o tempo de execução total por classificação e retornando apenas as classificações com um tempo de execução total maior ou igual a 100000:
db.movies.aggregate( [ // First Stage { $group: { _id: "$rated", totalRuntime: { $sum: "$runtime" } } }, // Second Stage { $match: { "totalRuntime": { $gte: 100000 } } } ] )
[ { _id: 'PG-13', totalRuntime: 250843 }, { _id: 'R', totalRuntime: 582318 }, { _id: null, totalRuntime: 967127 }, { _id: 'PG', totalRuntime: 191204 } ]
- Primeiro estágio:
- O estágio agrupa os documentos
$groupporratedpara recuperar os valores de classificação distintos. Este estágio retornatotalRuntimepara cada grupo de classificação. - Segundo estágio:
- O estágio filtra os documentos resultantes para retornar somente classificações
$matchcomtotalRuntimemaior ou igual 100000 a.
Esta operação de agregação é equivalente à seguinte declaração SQL:
SELECT rated, Sum(runtime) AS totalRuntime FROM movies GROUP BY rated HAVING totalRuntime >= 100000
Dica
Calcular Count, Sum, e Average
Agrupar por ano
O pipeline a seguir calcula o tempo de execução total, o tempo médio de execução e a contagem de filmes para cada ano anterior a 1910:
db.movies.aggregate([ { $match: { "year": { $lt: 1910 } } }, { $group: { _id: "$year", totalRuntime: { $sum: "$runtime" }, averageRuntime: { $avg: "$runtime" }, count: { $sum: 1 } } }, { $sort: { totalRuntime: -1 } } ])
[ { _id: 1909, totalRuntime: 14, averageRuntime: 14, count: 1 }, { _id: 1903, totalRuntime: 11, averageRuntime: 11, count: 1 }, { _id: 1896, totalRuntime: 2, averageRuntime: 1, count: 2 } ]
- Primeiro estágio:
- O estágio filtra os documentos para passar apenas os filmes lançados antes
$matchde 1910 para o próximo estágio. - Segundo estágio:
- A etapa agrupa os documentos por ano e calcula o tempo de execução total, o tempo médio de execução e a contagem total dos documentos em cada
$groupgrupo. - Terceiro estágio:
- O estágio classifica os resultados pelo tempo de execução total para cada grupo em ordem
$sortdecrescente.
Esta operação de agregação é equivalente à seguinte declaração SQL:
SELECT year, Sum(runtime) AS totalRuntime, Avg(runtime) AS averageRuntime, Count(*) AS count FROM movies WHERE year < 1910 GROUP BY year ORDER BY totalRuntime DESC
Dica
db.collection.countDocuments()que envolve o estágio de agregação$groupcom uma expressão$sum.
Agrupar por null
A operação de agregação a seguir especifica um grupo _id de null, calculando o tempo de execução total, o tempo médio de execução e a contagem de todos os documentos na coleta.
db.movies.aggregate([ { $group: { _id: null, totalRuntime: { $sum: "$runtime" }, averageRuntime: { $avg: "$runtime" }, count: { $sum: 1 } } } ])
[ { _id: null, totalRuntime: 2167458, averageRuntime: 103.65652797704448, count: 21349 } ]
Esta operação de agregação é equivalente à seguinte declaração SQL:
SELECT Sum(runtime) AS totalRuntime, Avg(runtime) AS averageRuntime, Count(*) AS count FROM movies
Dica
db.collection.countDocuments()que envolve o estágio de agregação$groupcom uma expressão$sum.
Dados dinâmicos
Agrupar títulos por ano
A seguinte operação de agregação dinamiza os dados na coleção movies para agrupar títulos por ano:
db.movies.aggregate([ { $match: { year: { $lt: 1910 } } }, { $group: { _id: "$year", titles: { $push: "$title" } } }, { $sort: { _id: 1 } } ])
[ { _id: 1896, titles: [ 'The Kiss', 'The Kiss' ] }, { _id: 1903, titles: [ 'The Great Train Robbery' ] }, { _id: 1909, titles: [ 'A Corner in Wheat' ] } ]
Agrupar documentos por ano
A seguinte operação de agregação agrupa documentos por ano:
db.movies.aggregate([ { $match: { year: { $lt: 1910 } } }, { $group: { _id: "$year", movies: { $push: "$$ROOT" } } }, { $addFields: { totalRuntime: { $sum: "$movies.runtime" } } }, { $sort: { _id: 1 } } ])
[ { _id: 1896, movies: '...', totalRuntime: 2 }, { _id: 1903, movies: '...', totalRuntime: 11 }, { _id: 1909, movies: '...', totalRuntime: 14 } ]
- Primeiro estágio:
$matchfiltra os documentos para passar apenas os filmes lançados antes de 1910 para o próximo estágio.- Segundo estágio:
$groupusa a$$ROOTvariável de sistema para agrupar os documentos inteiros por ano.- Terceiro estágio:
$addFieldsadiciona um campo à saída contendo o tempo de execução total de filmes para cada ano.Observação
Os documentos resultantes não devem exceder o limite de Tamanho do documento BSON de 16 mebibytes.
- Quarto estágio:
$sortclassifica os documentos resultantes por_idem ordem crescente.
Os exemplos de C# nesta página utilizam o banco de dados sample_mflix a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster MongoDB Atlas gratuito e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver MongoDB .NET/C#.
A seguinte classe Movie modela os documentos na collection sample_mflix.movies:
public class Movie { public ObjectId Id { get; set; } public int Runtime { get; set; } public string Title { get; set; } public string Rated { get; set; } public List<string> Genres { get; set; } public string Plot { get; set; } public ImdbData Imdb { get; set; } public int Year { get; set; } public int Index { get; set; } public string[] Comments { get; set; } [] public DateTime LastUpdated { get; set; } }
Observação
ConventionPack para Pascal Case
As classes C# nesta página usam Pascal case para seus nomes de propriedade, mas os nomes de campo na coleção MongoDB usam Camel case. Para considerar essa diferença, você pode usar o seguinte código para registrar um ConventionPack quando o aplicativo iniciar:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
Para usar o driver MongoDB .NET/C# para adicionar um estágio $group a uma agregação pipeline, chame o método Group() em um objeto PipelineDefinition.
O exemplo a seguir cria um estágio de pipeline que agrupa documentos pelo valor de seu campo Rated. A classificação de cada grupo é mostrada em um campo chamado Rating em cada documento de saída. Cada documento de saída também contém campos chamados TotalRuntime, MedianRuntime e NinetiethPercentileRuntime, que armazenam o total, a mediana e o 90º percentil de tempo de execução para filmes em cada grupo.
var pipeline = new EmptyPipelineDefinition<Movie>() .Group( id: m => m.Rated, group: g => new { Rating = g.Key, TotalRuntime = g.Sum(m => m.Runtime), MedianRuntime = g.Select(m => m.Runtime).Median(), NinetiethPercentileRuntime = g.Select(m => m.Runtime).Percentile(new[] { 0.9 }) } );
Os exemplos do Node.js nesta página utilizam o banco de dados do sample_mflix a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster gratuito do MongoDB Atlas e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver do MongoDB Node.js
Para usar o driver Node.js do MongoDB para adicionar um estágio $group a um pipeline de agregação , use o operador $group em um objeto de pipeline.
O exemplo a seguir cria um estágio de pipeline que agrupa documentos pelo valor de seu campo rated. Cada documento de saída contém um campo rating que armazena a classificação de cada grupo. Cada documento de saída também contém um campo chamado totalRuntime que armazena o tempo de execução total de todos os filmes do grupo. Em seguida, o exemplo executa o agregação pipeline:
const pipeline = [ { $group: { _id: "$rated", rating: { $first: "$rated" }, totalRuntime: { $sum: "$runtime" } } } ]; const cursor = collection.aggregate(pipeline); return cursor;
Saiba mais
O tutorial Grupo e dados totais fornece um exemplo extensivo do operador $group em um caso de uso comum.
Para saber mais sobre os estágios de pipeline relacionados, consulte o guia$addFields.