$group în MongoDB & NoSQL

Agregare & Analytics MongoDB 2.2

Etapa $group grupează documentele după o cheie și calculează totaluri: $sum, $avg, $min, $max, $push, $addToSet.

Sintaxă
{ $group: { _id: <expresie>, <camp>: { <acumulator>: <expresie> }, ... } }

Ce face $group

$group creează câte un document pentru fiecare valoare distinctă a lui _id. _id: '$oras' grupează după oraș, _id: null pune toate documentele într-un singur grup, iar un obiect (_id: { oras: '$oras', status: '$status' }) grupează după mai multe câmpuri.

Celelalte câmpuri sunt acumulatori: $sum: 1 numără documentele, $sum: '$total' adună valori, $avg, $min, $max calculează statistici, $push strânge valorile într-un tablou, iar $addToSet doar valorile unice. Ordinea grupurilor din rezultat nu este garantată: adaugă un $sort.

Parametri

Parametru Descriere
_id Cheia de grupare ('$camp', un obiect sau null).
$sum / $avg / $min / $max Sumă, medie, minim, maxim.
$push / $addToSet Tablou cu toate valorile / cu valorile unice.
$first / $last Prima / ultima valoare din grup (după ordinea de intrare).

Ce returnează

Câte un document pe grup, cu _id și câmpurile calculate.

Exemple

Exemplele de pe această pagină pornesc de la datele de mai jos. Rulează mai întâi acest cod, apoi exemplul.

use magazin
db.comenzi.insertMany([
  { _id: 1, client: 'Ana', oras: 'Iași', total: 120, status: 'livrata', produse: ['caiet', 'pix'] },
  { _id: 2, client: 'Dan', oras: 'Cluj', total: 85, status: 'noua', produse: ['carte'] },
  { _id: 3, client: 'Ioana', oras: 'Iași', total: 240, status: 'livrata', produse: ['rucsac', 'caiet', 'pix'] },
  { _id: 4, client: 'Mihai', oras: 'Brașov', total: 60, status: 'anulata', produse: [] }
])

Exemplul 1: Vânzări pe oraș

Numărul de comenzi și suma totală pentru fiecare oraș, ordonate descrescător după sumă.

db.comenzi.aggregate([
  { $group: { _id: '$oras', comenzi: { $sum: 1 }, total: { $sum: '$total' } } },
  { $sort: { total: -1 } }
])

Ieșire în mongosh

[
  { _id: 'Iași', comenzi: 2, total: 360 },
  { _id: 'Cluj', comenzi: 1, total: 85 },
  { _id: 'Brașov', comenzi: 1, total: 60 }
]

Exemplul 2: Statistici pe toată colecția

Cu _id: null rezultă un singur grup: media este 505 / 4.

db.comenzi.aggregate([{ $group: { _id: null, medie: { $avg: '$total' }, minim: { $min: '$total' }, maxim: { $max: '$total' } } }])

Ieșire în mongosh

[ { _id: null, medie: 126.25, minim: 60, maxim: 240 } ]

Exemplul 3: Clienții pe fiecare status

$push strânge numele clienților în ordinea în care intră în grup.

db.comenzi.aggregate([{ $sort: { _id: 1 } }, { $group: { _id: '$status', clienti: { $push: '$client' } } }, { $sort: { _id: 1 } }])

Ieșire în mongosh

[
  { _id: 'anulata', clienti: [ 'Mihai' ] },
  { _id: 'livrata', clienti: [ 'Ana', 'Ioana' ] },
  { _id: 'noua', clienti: [ 'Dan' ] }
]

Greșeli frecvente

  • Uiți $ din fața numelui: $sum: 'total' adună un text, deci rezultatul este 0.
  • Fiecare grup trebuie să încapă în memorie; pe colecții mari, $push cu multe valori poate depăși limitele. MongoDB folosește discul temporar când e nevoie (allowDiskUse este activ implicit din MongoDB 6.0).

Comenzi înrudite

  • $match: Etapa $match păstrează în pipeline doar documentele care se potrivesc filtrului, cu aceeași sintaxă ca find().
  • $sort / $limit / $skip: Etapele $sort, $skip și $limit ordonează documentele din pipeline și aleg o porțiune din ele (top N, paginare).
  • $unwind: Etapa $unwind desface un tablou: produce câte un document pentru fiecare element, ca să-l poți grupa sau filtra.
  • distinct(): Întoarce valorile unice ale unui câmp din colecție, opțional doar pentru documentele care se potrivesc unui filtru.
  • $bucket / $bucketAuto: Etapa $bucket grupează documentele pe intervale de valori (de exemplu de preț); $bucketAuto alege singură intervalele.