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

$group (agregação)

Nesta página

  • Definição
  • Compatibilidade
  • Sintaxe
  • Considerações
  • Exemplos
  • Recursos adicionais
$group

O estágio $group separa os documentos em grupos de acordo com uma "chave de grupo". A saída é um documento para cada 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 _id no estágio de pipeline $group para 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

$group não ordena seus documentos de saída.

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

O estágio $group tem a seguinte forma de protótipo:

{
$group:
{
_id: <expression>, // Group key
<field1>: { <accumulator1> : <expression1> },
...
}
}
Campo
Descrição

_id

Obrigatório. A _id expressão especifica a chave do grupo. Se você especificar um _id valor nulo ou qualquer outro valor constante, o $group estágio retornará um único documento que agrega valores em todos os documentos de entrada. Veja o exemplo Grupo por Nulo.

field

Opcional. Computado usando os operadores acumulador .

O _id e os operadores acumuladores podem aceitar qualquer expression válida. Para obter mais informações sobre expressões, consulte Operadores de expressão.

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

O operador <accumulator> deve ser um dos seguintes operadores acumuladores:

Alterado na versão 5.0.

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 $setWindowFields.

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 $setWindowFields.

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 $group e $setWindowFields.

Retorna uma agregação dos campos n inferiores dentro de um grupo, de acordo com a ordem de classificação especificada.

Novidades na versão 5.2.

Disponível nos estágios $group e $setWindowFields.

Retorna o número de documentos em um grupo.

Diferente do estágio $count do pipeline.

Novidade na versão 5.0: Disponível nos estágios $group e $setWindowFields.

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 $setWindowFields.

Retorna uma agregação dos primeiros n elementos dentro de um grupo. Só faz sentido quando os documentos estão em uma ordem definida. Diferente do operador de array $firstN.

Novidade na versão 5.2: Disponível nos estágios $group, expressão e $setWindowFields.

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 $setWindowFields.

Retorna uma agregação dos últimos n elementos dentro de um grupo. Só faz sentido quando os documentos estão em uma ordem definida. Diferente do operador de array $lastN.

Novidade na versão 5.2: Disponível nos estágios $group, expressão e $setWindowFields.

Retorna o valor de expressão mais alto para cada grupo.

Alterado na versão 5.0: Disponível no estágio $setWindowFields.

Retorna uma agregação dos n elementos com valor máximo em um grupo. Diferente do operador de array $maxN.

Novidades na versão 5.2.

Disponível em $group, $setWindowFields e como uma expressão.

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 $setWindowFields.

Retorna uma agregação dos n elementos com valor mínimo em um grupo. Distinto do operador de array $minN .

Novidades na versão 5.2.

Disponível em $group, $setWindowFields e como uma expressão.

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 $setWindowFields.

Retorna o desvio padrão da população dos valores de entrada.

Alterado na versão 5.0: Disponível no estágio $setWindowFields.

Retorna o desvio padrão da amostra dos valores de entrada.

Alterado na versão 5.0: Disponível no estágio $setWindowFields.

Retorna uma soma de valores numéricos. Ignora valores não numéricos.

Alterado na versão 5.0: Disponível no estágio $setWindowFields.

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 $group e $setWindowFields.

Retorna uma agregação dos principais campos n dentro de um grupo, de acordo com a ordem de classificação especificada.

Novidades na versão 5.2.

Disponível nos estágios $group e $setWindowFields.

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.

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.

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 uma coleção chamada foo contiver um índice { x: 1, y: 1 }, o pipeline a seguir poderá usar esse índice para localizar o primeiro documento de cada grupo:

db.foo.aggregate([
{
$sort:{ x : 1, y : 1 }
},
{
$group: {
_id: { x : "$x" },
y: { $first : "$y" }
}
}
])

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.

No mongosh, crie uma coleção de amostra denominada sales com os seguintes documentos:

db.sales.insertMany([
{ "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") },
{ "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") },
{ "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") },
{ "_id" : 4, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") },
{ "_id" : 5, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") },
{ "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") },
{ "_id" : 7, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") },
{ "_id" : 8, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") },
])

A operação de agregação a seguir usa o estágio $group para contar o número de documentos na coleção sales:

db.sales.aggregate( [
{
$group: {
_id: null,
count: { $count: { } }
}
}
] )

A operação retorna o seguinte resultado:

{ "_id" : null, "count" : 8 }

Esta operação de agregação é equivalente à seguinte declaração SQL:

SELECT COUNT(*) AS count FROM sales

Dica

Veja também:

A seguinte operação de agregação utiliza o estágio $group para recuperar os valores de item distintos da coleção sales:

db.sales.aggregate( [ { $group : { _id : "$item" } } ] )

A operação retorna o seguinte resultado:

{ "_id" : "abc" }
{ "_id" : "jkl" }
{ "_id" : "def" }
{ "_id" : "xyz" }

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.

A seguinte operação de agregação agrupa documentos pelo campo item , calculando o valor total de venda por item e retornando apenas os itens com valor total de venda maior ou igual a 100:

db.sales.aggregate(
[
// First Stage
{
$group :
{
_id : "$item",
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }
}
},
// Second Stage
{
$match: { "totalSaleAmount": { $gte: 100 } }
}
]
)
Primeiro estágio:
O estágio $group agrupa os documentos por item para recuperar os valores distintos dos itens. Este estágio retorna totalSaleAmount para cada item.
Segundo estágio:
O estágio $match filtra os documentos resultantes para retornar somente itens com um totalSaleAmount maior ou igual a 100.

A operação retorna o seguinte resultado:

{ "_id" : "abc", "totalSaleAmount" : Decimal128("170") }
{ "_id" : "xyz", "totalSaleAmount" : Decimal128("150") }
{ "_id" : "def", "totalSaleAmount" : Decimal128("112.5") }

Esta operação de agregação é equivalente à seguinte declaração SQL:

SELECT item,
Sum(( price * quantity )) AS totalSaleAmount
FROM sales
GROUP BY item
HAVING totalSaleAmount >= 100

Dica

Veja também:

No mongosh, crie uma coleção de amostra denominada sales com os seguintes documentos:

db.sales.insertMany([
{ "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") },
{ "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") },
{ "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") },
{ "_id" : 4, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") },
{ "_id" : 5, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") },
{ "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") },
{ "_id" : 7, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") },
{ "_id" : 8, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") },
])

O pipeline a seguir calcula o valor total de vendas, a quantidade média de vendas e a contagem de vendas para cada dia do ano de 2014:

db.sales.aggregate([
// First Stage
{
$match : { "date": { $gte: new ISODate("2014-01-01"), $lt: new ISODate("2015-01-01") } }
},
// Second Stage
{
$group : {
_id : { $dateToString: { format: "%Y-%m-%d", date: "$date" } },
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } },
averageQuantity: { $avg: "$quantity" },
count: { $sum: 1 }
}
},
// Third Stage
{
$sort : { totalSaleAmount: -1 }
}
])
Primeiro estágio:
O estágio $match filtra os documentos para passar apenas os documentos do ano 2014 para o próximo estágio.
Segundo estágio:
A etapa $group agrupa os documentos por data e calcula o valor total da venda, a quantidade média e a contagem total dos documentos em cada grupo.
Terceiro estágio:
O estágio $sort classifica os resultados pelo valor total da venda para cada grupo em ordem decrescente.

A operação retorna os seguintes resultados:

{
"_id" : "2014-04-04",
"totalSaleAmount" : Decimal128("200"),
"averageQuantity" : 15, "count" : 2
}
{
"_id" : "2014-03-15",
"totalSaleAmount" : Decimal128("50"),
"averageQuantity" : 10, "count" : 1
}
{
"_id" : "2014-03-01",
"totalSaleAmount" : Decimal128("40"),
"averageQuantity" : 1.5, "count" : 2
}

Esta operação de agregação é equivalente à seguinte declaração SQL:

SELECT date,
Sum(( price * quantity )) AS totalSaleAmount,
Avg(quantity) AS averageQuantity,
Count(*) AS Count
FROM sales
WHERE date >= '01/01/2014' AND date < '01/01/2015'
GROUP BY date
ORDER BY totalSaleAmount DESC

Dica

Veja também:

A operação de agregação a seguir especifica um grupo _id de null, calculando o valor total da venda, a quantidade média e a contagem de todos os documentos na coleção.

db.sales.aggregate([
{
$group : {
_id : null,
totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } },
averageQuantity: { $avg: "$quantity" },
count: { $sum: 1 }
}
}
])

A operação retorna o seguinte resultado:

{
"_id" : null,
"totalSaleAmount" : Decimal128("452.5"),
"averageQuantity" : 7.875,
"count" : 8
}

Esta operação de agregação é equivalente à seguinte declaração SQL:

SELECT Sum(price * quantity) AS totalSaleAmount,
Avg(quantity) AS averageQuantity,
Count(*) AS Count
FROM sales

Dica

Veja também:

No mongosh, crie uma coleção de amostra denominada books com os seguintes documentos:

db.books.insertMany([
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 },
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }
])

A seguinte operação de agregação dinamiza os dados na coleção books para ter títulos agrupados por autores.

db.books.aggregate([
{ $group : { _id : "$author", books: { $push: "$title" } } }
])

A operação retorna os seguintes documentos:

{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] }
{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }

A seguinte operação de agregação agrupa documentos por author:

db.books.aggregate([
// First Stage
{
$group : { _id : "$author", books: { $push: "$$ROOT" } }
},
// Second Stage
{
$addFields:
{
totalCopies : { $sum: "$books.copies" }
}
}
])
Primeiro estágio:

$group usa a variável de sistema $$ROOT para agrupar os documentos inteiros por autores. Esta etapa passa os seguintes documentos para a próxima etapa:

{ "_id" : "Homer",
"books" :
[
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }
]
},
{ "_id" : "Dante",
"books" :
[
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }
]
}
Segundo estágio:

$addFields adiciona um campo à saída contendo o total de cópias de livros de cada autor.

Observação

Os documentos resultantes não devem exceder o limite de Tamanho do documento BSON de 16 megabytes.

A operação retorna os seguintes documentos:

{
"_id" : "Homer",
"books" :
[
{ "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
{ "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }
],
"totalCopies" : 20
}
{
"_id" : "Dante",
"books" :
[
{ "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
{ "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 },
{ "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }
],
"totalCopies" : 5
}

Dica

Veja também:

O tutorial Agregação com o conjunto de dados de código postal fornece um exemplo extensivo do operador $group em um caso de uso comum.

Voltar

$graphLookup