Best Studio 1
Best Studio
mannaxxx 1
mannaxxx
Agora Metin2 1
Agora Metin2
[DEV]AB 1
[DEV]AB
Sevdamsın 1
Sevdamsın
TuZaKK 1
TuZaKK
kaptanmikro1 1
kaptanmikro1
farkmt2official 2
farkmt2official
kralhakan2009 1
kralhakan2009
Vahsi Uzman 1
Vahsi Uzman
Bvural41 1
Bvural41
Hikaye Ekle

[NODE JS] MongoDB Aggregation Pipeline

Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!

nodejs.png


[NODE JS] MongoDB Aggregation Pipeline​


MongoDB'nin Aggregation Pipeline'ı, veritabanı dünyasında benim en çok hayran kaldığım özelliklerden biri. İlk başta biraz karmaşık görünebilir ama bir kez mantığını kavradığınızda, veriler üzerinde inanılmaz güçlü dönüşümler yapabiliyorsunuz. SQL'deki GROUP BY, JOIN, HAVING gibi işlemlerin hepsini ve çok daha fazlasını tek bir pipeline ile gerçekleştirebilirsiniz.

Aggregation Pipeline, adından da anlaşılacağı gibi bir boru hattı mantığıyla çalışır. Veriler bir aşamadan (stage) geçer, dönüştürülür ve bir sonraki aşamaya aktarılır. Her aşama belirli bir işlem yapar: filtreleme, gruplama, sıralama, projeksiyon, birleştirme gibi. Bu aşamaları zincirleme olarak kullanarak karmaşık veri analizleri gerçekleştirebiliriz.

En sık kullandığımız aşamalar şunlardır: $match filtreleme için kullanılır ve SQL'deki WHERE ifadesine benzer. $group verileri belirli bir alana göre gruplar ve toplama işlemleri yapar. $sort sıralama, $project alan seçimi ve dönüştürme, $limit ve $skip sayfalama, $unwind dizi alanlarını açma, $lookup ise farklı koleksiyonlar arasında birleştirme (join) işlemi için kullanılır.

Performans açısından dikkat edilmesi gereken önemli noktalar var. $match aşamasını mümkün olduğunca pipeline'ın başına koymak, işlenecek veri miktarını azaltır. İndekslerden faydalanmak için $match ve $sort aşamalarını pipeline'ın erken safhalarında kullanmak kritik. Ayrıca $project ile sadece ihtiyaç duyulan alanları seçmek bellek kullanımını optimize eder.

$lookup aşaması, ilişkisel veritabanlarındaki JOIN işleminin MongoDB karşılığıdır. İki farklı koleksiyonu birleştirmemize olanak tanır. Ancak büyük veri setlerinde dikkatli kullanılmalıdır çünkü performans üzerinde önemli etkisi olabilir. Pipeline lookup özelliği sayesinde birleştirme sırasında ek filtreleme ve dönüşümler de yapılabilir.

$facet aşaması çok güçlü bir özelliktir. Tek bir pipeline içinde birden fazla bağımsız aggregation pipeline çalıştırmanıza olanak tanır. Örneğin aynı veri seti üzerinde hem kategori bazlı toplam, hem yaş dağılımı, hem de en son kayıtları aynı anda hesaplayabilirsiniz. Bu özellik özellikle dashboard ve raporlama sayfalarında çok işe yarar.

Gerçek dünya senaryolarında aggregation pipeline'ları sıkça kullanırız: aylık satış raporları, kullanıcı davranış analizleri, envanter takibi, log analizi gibi birçok alanda. Mongoose'un aggregate() metodu ile bu pipeline'ları kolayca oluşturabilir ve çalıştırabiliriz. Sonuçları önbelleğe almak da performans için iyi bir stratejidir.

JavaScript:
// MongoDB Aggregation Pipeline - Kapsamlı Örnekler
const mongoose = require('mongoose');

// Veritabanı bağlantısı
mongoose.connect('mongodb://localhost:27017/magaza_db');

// Ürün şeması
const urunSemasi = new mongoose.Schema({
  ad: String,
  kategori: String,
  fiyat: Number,
  stok: Number,
  saticiId: mongoose.Schema.Types.ObjectId,
  etiketler: [String],
  ozellikler: {
    renk: String,
    beden: String,
    agirlik: Number
  },
  degerlendirmeler: [{
    kullaniciId: mongoose.Schema.Types.ObjectId,
    puan: Number,
    yorum: String,
    tarih: Date
  }],
  olusturmaTarihi: { type: Date, default: Date.now }
});

const Urun = mongoose.model('Urun', urunSemasi);

// Sipariş şeması
const siparisSemasi = new mongoose.Schema({
  kullaniciId: mongoose.Schema.Types.ObjectId,
  urunler: [{
    urunId: mongoose.Schema.Types.ObjectId,
    adet: Number,
    birimFiyat: Number
  }],
  toplamTutar: Number,
  durum: String,
  siparisTarihi: { type: Date, default: Date.now }
});

const Siparis = mongoose.model('Siparis', siparisSemasi);

// 1. Temel Gruplama ve Toplama İşlemleri
async function kategoriBazliAnaliz() {
  const sonuclar = await Urun.aggregate([
    // Sadece aktif ürünleri filtrele
    { $match: { stok: { $gt: 0 } } },

    // Kategoriye göre grupla
    {
      $group: {
        _id: '$kategori',
        toplamUrun: { $sum: 1 },
        ortalama Fiyat: { $avg: '$fiyat' },
        enYuksekFiyat: { $max: '$fiyat' },
        enDusukFiyat: { $min: '$fiyat' },
        toplamStok: { $sum: '$stok' },
        toplamDeger: { $sum: { $multiply: ['$fiyat', '$stok'] } }
      }
    },

    // Toplam değere göre sırala
    { $sort: { toplamDeger: -1 } },

    // Çıktıyı düzenle
    {
      $project: {
        kategori: '$_id',
        _id: 0,
        toplamUrun: 1,
        ortalamaFiyat: { $round: ['$ortalamaFiyat', 2] },
        enYuksekFiyat: 1,
        enDusukFiyat: 1,
        toplamStok: 1,
        toplamDeger: { $round: ['$toplamDeger', 2] }
      }
    }
  ]);

  console.log('Kategori bazlı analiz:', JSON.stringify(sonuclar, null, 2));
  return sonuclar;
}

// 2. $lookup ile Koleksiyonları Birleştirme
async function siparisDetaylari() {
  const sonuclar = await Siparis.aggregate([
    // Son 30 günün siparişleri
    {
      $match: {
        siparisTarihi: {
          $gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
        }
      }
    },

    // Sipariş ürünlerini aç
    { $unwind: '$urunler' },

    // Ürün detaylarını birleştir
    {
      $lookup: {
        from: 'uruns',
        localField: 'urunler.urunId',
        foreignField: '_id',
        as: 'urunDetay'
      }
    },

    // Ürün detay dizisini aç
    { $unwind: '$urunDetay' },

    // İstenen alanları seç
    {
      $project: {
        siparisTarihi: 1,
        durum: 1,
        urunAdi: '$urunDetay.ad',
        kategori: '$urunDetay.kategori',
        adet: '$urunler.adet',
        birimFiyat: '$urunler.birimFiyat',
        satirToplam: {
          $multiply: ['$urunler.adet', '$urunler.birimFiyat']
        }
      }
    },

    // Satır toplamına göre sırala
    { $sort: { satirToplam: -1 } },

    { $limit: 20 }
  ]);

  console.log('Sipariş detayları:', sonuclar.length, 'kayıt');
  return sonuclar;
}

// 3. $facet ile Çoklu Analiz
async function dashboardVerileri() {
  const sonuclar = await Urun.aggregate([
    {
      $facet: {
        // Kategori dağılımı
        kategoriDagilimi: [
          { $group: { _id: '$kategori', adet: { $sum: 1 } } },
          { $sort: { adet: -1 } }
        ],

        // Fiyat aralıkları
        fiyatAraliklari: [
          {
            $bucket: {
              groupBy: '$fiyat',
              boundaries: [0, 50, 100, 250, 500, 1000, Infinity],
              default: 'Diğer',
              output: {
                adet: { $sum: 1 },
                ortalama: { $avg: '$fiyat' }
              }
            }
          }
        ],

        // Genel istatistikler
        genelIstatistikler: [
          {
            $group: {
              _id: null,
              toplamUrun: { $sum: 1 },
              ortalamaFiyat: { $avg: '$fiyat' },
              toplamStokDegeri: {
                $sum: { $multiply: ['$fiyat', '$stok'] }
              }
            }
          }
        ],

        // Son eklenen ürünler
        sonEklenenler: [
          { $sort: { olusturmaTarihi: -1 } },
          { $limit: 5 },
          { $project: { ad: 1, kategori: 1, fiyat: 1 } }
        ]
      }
    }
  ]);

  console.log('Dashboard verileri hazır');
  return sonuclar[0];
}

// 4. Değerlendirme Analizi - $unwind ve Gruplama
async function degerlendirmeAnalizi() {
  const sonuclar = await Urun.aggregate([
    // Değerlendirmeleri olan ürünleri filtrele
    { $match: { 'degerlendirmeler.0': { $exists: true } } },

    // Değerlendirme dizisini aç
    { $unwind: '$degerlendirmeler' },

    // Ürün bazında grupla
    {
      $group: {
        _id: { urunId: '$_id', urunAdi: '$ad' },
        ortalamaPuan: { $avg: '$degerlendirmeler.puan' },
        toplamDegerlendirme: { $sum: 1 },
        enYuksekPuan: { $max: '$degerlendirmeler.puan' },
        enDusukPuan: { $min: '$degerlendirmeler.puan' }
      }
    },

    // Ortalama puana göre sırala
    { $sort: { ortalamaPuan: -1 } },

    // Çıktıyı düzenle
    {
      $project: {
        _id: 0,
        urunAdi: '$_id.urunAdi',
        ortalamaPuan: { $round: ['$ortalamaPuan', 1] },
        toplamDegerlendirme: 1,
        puanAraligi: {
          $subtract: ['$enYuksekPuan', '$enDusukPuan']
        }
      }
    },

    { $limit: 10 }
  ]);

  console.log('En iyi değerlendirilen ürünler:', sonuclar);
  return sonuclar;
}

// 5. Aylık Satış Raporu
async function aylikSatisRaporu() {
  const sonuclar = await Siparis.aggregate([
    // Tamamlanan siparişler
    { $match: { durum: 'tamamlandi' } },

    // Ay bazında grupla
    {
      $group: {
        _id: {
          yil: { $year: '$siparisTarihi' },
          ay: { $month: '$siparisTarihi' }
        },
        toplamSatis: { $sum: '$toplamTutar' },
        siparisSayisi: { $sum: 1 },
        ortalamaSepeT: { $avg: '$toplamTutar' }
      }
    },

    // Tarihe göre sırala
    { $sort: { '_id.yil': -1, '_id.ay': -1 } },

    // Çıktıyı oku
    {
      $project: {
        _id: 0,
        donem: {
          $concat: [
            { $toString: '$_id.yil' },
            '-',
            {
              $cond: {
                if: { $lt: ['$_id.ay', 10] },
                then: { $concat: ['0', { $toString: '$_id.ay' }] },
                else: { $toString: '$_id.ay' }
              }
            }
          ]
        },
        toplamSatis: { $round: ['$toplamSatis', 2] },
        siparisSayisi: 1,
        ortalamaSepet: { $round: ['$ortalamaSepeT', 2] }
      }
    }
  ]);

  console.log('Aylık satış raporu:', sonuclar);
  return sonuclar;
}

// Tüm analizleri çalıştır
async function main() {
  try {
    await kategoriBazliAnaliz();
    await siparisDetaylari();
    await dashboardVerileri();
    await degerlendirmeAnalizi();
    await aylikSatisRaporu();
  } catch (hata) {
    console.error('Aggregation hatası:', hata.message);
  } finally {
    await mongoose.connection.close();
  }
}

main();

Aggregation Pipeline, MongoDB'nin en güçlü özelliklerinden biridir ve karmaşık veri analizleri için vazgeçilmez bir araçtır. Başlangıçta pipeline aşamalarını anlamak zaman alabilir ama pratik yaptıkça çok doğal gelmeye başlıyor. Özellikle $facet ve $lookup gibi gelişmiş aşamalar, uygulamalarınızda profesyonel düzeyde raporlama ve analiz yetenekleri kazandırır.
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst