MongoDB Aggregation Pipeline Veri İşleme
Aggregation pipeline, MongoDB'nin veri dönüştürme motorudur. Belgeler bir boruya girer, aşama aşama işlenir, sonuçta istediğiniz şekle bürünür. SQL tarafında GROUP BY, JOIN ve HAVING ile yaptığınız işlerin çoğu burada birer aşamaya karşılık gelir.
Bu rehberi okurken elinizde çalışan bir MongoDB olsun. Yoksa Docker ile tek komutta bir mongo konteyneri ayağa kaldırabilirsiniz; containerization başlangıç notlarımızdaki mantık burada da işe yarar. Örnekleri siparisler adında bir koleksiyon üzerinden anlatacağım. Alanlar: musteriId, tutar, durum, urunler[], olusturmaTarihi.
Pipeline Mantığını Aşama Aşama Kurmak
Pipeline bir dizidir. Her elemanı bir aşamadır. Aşamalar sırayla çalışır. Bir aşamanın çıktısı, sonraki aşamanın girdisidir. Bu yüzden sıralama, sonucu da hızı da belirler.
Temel aşamaları tanıyın
Önce sık kullanılan aşamaları ezberlemeden kavrayın:
| Aşama | Ne yapar | SQL karşılığı |
|---|---|---|
| $match | Belge filtreler | WHERE |
| $project | Alan seçer, yeni alan üretir | SELECT |
| $group | Gruplar ve toplar | GROUP BY |
| $sort | Sıralar | ORDER BY |
| $limit / $skip | Sayfalama | LIMIT / OFFSET |
| $lookup | Başka koleksiyonla birleştirir | LEFT JOIN |
| $unwind | Diziyi belgelere açar | — |
İlk gerçek pipeline'ınız şöyle olabilir:
- 1. aşama: $match ile durumu "tamamlandi" olanları al.
- 2. aşama: $group ile musteriId'ye göre grupla, $sum ile tutarları topla.
- 3. aşama: $sort ile toplam tutara göre azalan sırala.
- 4. aşama: $limit ile ilk 10 müşteriyi bırak.
Yazımı: db.siparisler.aggregate([{ $match: { durum: "tamamlandi" } }, { $group: { _id: "$musteriId", toplam: { $sum: "$tutar" }, adet: { $sum: 1 } } }, { $sort: { toplam: -1 } }, { $limit: 10 }])
$group içinde akümülatörleri kullanın
$group'un gücü akümülatörlerde. Sık kullanılanlar:
- $sum: Toplam. Sayaç için $sum: 1 yazın.
- $avg: Ortalama. Sepet ortalaması için ideal.
- $min / $max: Uç değerler. İlk ve son sipariş tarihi gibi.
- $push: Grup içindeki değerleri diziye atar.
- $addToSet: Tekrarsız dizi üretir. Kaç farklı ürün alındı sorusunun cevabı.
- $first / $last: Sıralı veride ilk ve son belgeyi taşır.
_id alanı grup anahtarıdır. Birden fazla alana göre gruplamak isterseniz nesne verin: _id: { musteri: "$musteriId", durum: "$durum" }. Tüm koleksiyonu tek grup yapmak için _id: null kullanın.
Dizileri ve tarihleri işleyin
Belgelerdeki diziler pipeline'da en çok kafa karıştıran kısımdır. Sırayı şöyle kurun:
- $unwind ile diziyi açın. Her eleman ayrı bir belge olur.
- Açılmış belgeleri $group ile yeniden toplayın.
- Gereksiz alanları $project ile kesin.
Tarih kırılımı için $dateToString veya $dateTrunc işinizi görür. Aylık ciro için: { $group: { _id: { $dateToString: { format: "%Y-%m", date: "$olusturmaTarihi" } }, ciro: { $sum: "$tutar" } } }. Metin içinde desen arayacaksanız $match içinde $regex kullanabilirsiniz; regex rehberindeki kalıplar burada da geçerlidir.
Performans ve Hata Ayıklama
Aggregation yazmak kolay, hızlı çalıştırmak beceri ister. Sorunların çoğu aşama sırasından ve eksik indeksten doğar.
Filtreyi öne alın, indeksi kullanın
- $match'i ilk aşamaya koyun. Sadece bu durumda indeks kullanılır.
- $sort da başta ise indeksten faydalanır. $group'tan sonraki $sort bellekte çalışır.
- $project veya $addFields ile alan adı değiştirdikten sonra o alanda indeks avantajı kalmaz.
- $limit'i mümkün olan en erken noktaya taşıyın.
- Bileşik indeks kurarken alan sırası önemlidir: eşitlik, sonra sıralama, sonra aralık. Veri tabanı optimizasyon ipuçlarındaki aynı mantık MongoDB için de geçerli.
explain ile ölçün
Tahmin etmeyin, bakın. db.siparisler.aggregate(pipeline, { explain: true }) çıktısında şunları arayın:
- COLLSCAN: Tüm koleksiyon taranıyor. İndeks eksik demektir.
- IXSCAN: İndeks kullanılıyor. İstediğiniz durum.
- İncelenen belge sayısı ile dönen belge sayısı arasındaki fark. Fark büyükse filtreniz geç çalışıyor.
- Bellek uyarıları. Aşama başına bellek sınırını aşarsanız allowDiskUse: true gerekir, ama bu bir çözü
© 2026 Yazılım Atölyesi