Ana içeriğe geç

Python ve PyMongo ile MongoDB Aggregation Pipeline Eğitimi

PyMongo kullanarak MongoDB aggregation pipeline’larını keşfedin. Veri akışını, $match, $project, $group, $lookup gibi aşamaları ve ileri düzey kalıpları anlayın.
· 15 dk. oku

Yapay Zeka ile Keşfedin

Büyük veri kümeleriyle çalışırken, performansı korurken anlamlı örüntüler ve içgörüler çıkarmak genellikle bir zorluktur. Uygulamalarınız veriyi MongoDB’de saklıyorsa, karmaşık sorguları ve dönüşümleri doğrudan veritabanında çalıştırmak, veriyi harici analiz araçlarına taşımaktan çok daha hızlı olabilir. MongoDB aggregation pipeline’ları, veriyi bulunduğu yerde işlemeye, dönüştürmeye ve analiz etmeye olanak tanıyarak bir çözüm sunar.

Basit işlemleri ardışık olarak bağlayarak özel veri işleme iş akışları oluşturabilirsiniz. Pipeline’daki her aşama belgeleri dönüştürür ve sonuçları bir sonraki aşamaya iletir. Örneğin, kayıtları tarih aralığına göre filtrelemeniz, kategorilere göre gruplamanız, istatistiksel ölçüler hesaplamanız ve çıktıyı biçimlendirmeniz gerekebilir—tüm bunlar, veriyi kaynağa en yakın noktada işleyen tek bir veritabanı işlemiyle başarılabilir.

Bu makalede, yaygın veri sorunlarını çözmek için aggregation pipeline’larını nasıl kuracağınızı öğreneceksiniz; tüm örnekler PyMongo (MongoDB’nin resmi Python istemcisi) ile gösterilmiştir. 

Bu makale aggregation pipeline’lara odaklansa da, MongoDB’yi Python ile kullanmaya Giriş kursu kapsamlı bir başlangıç sunar. Bu makaleden yeterli temeli edinerek burada anlatılan aggregation kavramlarını MongoDB’nin sorgu diline kendi başınıza ya da dil modellerinin yardımıyla aktarabilirsiniz.

MongoDB’de Aggregation Pipeline’lar nedir?

Müşteri memnuniyeti eğilimlerini anlamak için birden fazla ürüne ait müşteri yorumlarını analiz etmeniz gerektiğini düşünün. Geleneksel sorgular veriyi getirebilir, ancak bu bilgiyi yararlı özetlere dönüştürmek için birleştirme, analiz ve dönüştürme konusunda yardımcı olmazlar. 

MongoDB’nin aggregation pipeline’ları, birbirini tamamlayan bir dizi işlem aracılığıyla veriyi işlemenin yapılandırılmış bir yolunu sunarak bunu çözer.

Pipeline mimarisi ve belge akışı

MongoDB Aggregation Pipeline architecture

Aggregation pipeline’ları veriniz için birer montaj hattı gibi düşünün. Koleksiyonunuzdaki her belge pipeline’ın bir ucundan girer ve filtrelendiği, dönüştürüldüğü, gruplandığı veya zenginleştirildiği çeşitli istasyonlardan (aşamalardan) geçer. 

Bir aşamanın çıktısı bir sonrakinin girdisi olur; böylece karmaşık veri dönüşümlerini daha küçük ve yönetilebilir adımlara bölebilirsiniz.

Bu pipeline’lar deklaratif bir yaklaşım kullanır; her aşamada nasıl hesaplanacağını değil, ne istediğinizi belirtirsiniz. Bu yaklaşım, veri işleme niyetlerinizi netleştirir ve MongoDB’nin yürütme ayrıntılarını ele almasına olanak tanır. Veritabanı, pipeline yapınıza göre çeşitli optimizasyonlar uygulayabilir.

Pipeline tasarımınızda aşama sırası önemlidir. Belgeleri erken (gruplama veya karmaşık hesaplamalardan önce) filtrelemek, pipeline boyunca akan veri miktarını azaltır. 

Bu yaklaşım, büyük koleksiyonlarla çalışırken performansı kayda değer ölçüde iyileştirebilir. İyi yapılandırılmış bir pipeline, nihai sonuçlarınız için yalnızca gerekli veriyi işler.

  • Belge akışı: Belgeler girer → aşamalardan geçerek dönüşür → sonuçlar ortaya çıkar
  • Deklaratif tasarım: Nasıl hesaplanacağını değil, ne istediğinizi belirtin
  • Sıralı işleme: Her aşamanın çıktısı doğrudan bir sonrakine beslenir
  • Performans avantajı: Erken filtreleme, sonraki aşamalardaki veri hacmini azaltır

Aşama tipolojisi ve işlevsel kategoriler

MongoDB aggregation aşamaları amaçlarına göre dört ana kategoriye ayrılır. $match gibi filtreleme aşamaları, belirli ölçütleri karşılayan belgeleri seçerek sorgular gibi çalışır. Bu, daha karmaşık işlemlerden önce veri kümenizi daraltmaya yardımcı olur.

Yeniden şekillendirme aşamaları belge yapısını dönüştürür. $project veya $addFields kullanarak alanları dahil edebilir, hariç tutabilir, yeniden adlandırabilir ya da mevcut değerlerden hesaplanan alanlar oluşturabilirsiniz. Bu aşamalar, yalnızca ilgili bilgileri tutarak ve analiz için gereken hesaplanmış değerleri ekleyerek belgeleri basitleştirir.

Paylaşılan özelliklere göre birden çok belgeyi birleştirmeniz gerektiğinde gruplama aşamaları devreye girer. $group burada işin yükünü çeker; belgeler grupları arasında sayımlar, toplamlar, ortalamalar ve diğer toplulaştırılmış değerleri hesaplamanızı sağlar. Bu, binlerce bireysel kaydı analitik sorularınıza yanıt veren anlamlı özetlere dönüştürür.

Veri görünümünüzü tamamlamak için, $lookup gibi birleştirme aşamaları birden çok koleksiyondan bilgiyi bir araya getirmenize olanak tanır. Bu, SQL join’lerine benzer şekilde ancak MongoDB’nin belge modeline uyarlanmış olarak belgeleri ilişkili verilerle zenginleştirmenizi sağlar. Koleksiyonlar arası verilere başvurabilme yeteneği, doğru veri normalizasyonunu korurken tek bir işlemde eksiksiz sonuçlar sunmaya yardımcı olur.

  • Filtreleme: $match ile ölçütlere göre belirli belgeleri seçin
  • Yeniden şekillendirme: $project ve $addFields ile belge yapısını dönüştürün
  • Gruplama: $group ile birleştirip özetleyin, toplulaştırılmış değerler elde edin
  • Birleştirme: $lookup ile koleksiyonlar arası ilişkili verileri bağlayın

Yetenekler ve operatörler için tam başvuruya bakmak isterseniz MongoDB Aggregation Pipeline Kılavuzunu inceleyebilirsiniz.

Eğitim İçin Ortamı Hazırlama

MongoDB aggregation pipeline’larına dalmadan önce, PyMongo’nun kurulu olduğu ve örnek bir veri kümesine erişiminizin bulunduğu bir çalışma ortamına ihtiyacınız var. Bu bölüm, toplulaştırma kavramlarını göstermek için ideal olan finansal veriler içeren sample_analytics veri kümesiyle kurulum sürecini adım adım anlatır.

PyMongo’nun kurulumu

PyMongo, MongoDB’nin resmi Python sürücüsüdür. Hem macOS hem Windows’ta pip kullanarak kurabilirsiniz:

# Install PyMongo using pip
pip install pymongo

# Or if you're using conda
conda install -c conda-forge pymongo
  • Sürüm uyumluluğu: PyMongo 4.x, Python 3.7+ ile çalışır
  • Bağımlılık yönetimi: Yükleyici gerekli bağımlılıkları otomatik olarak halleder
  • Platform desteği: Windows, macOS ve Linux’ta aynı şekilde çalışır

Örnek veri kümesine erişim

MongoDB, kendi verinizi oluşturmadan kullanabileceğiniz örnek veri kümeleri sunar. En kolay yöntem MongoDB Atlas’ı (bulut sürümü) kullanmaktır:

  1. mongodb.com/cloud/atlas adresinde ücretsiz bir MongoDB Atlas hesabı oluşturun
  2. Ücretsiz katman (free tier) bir küme kurun

MongoDB Atlas cluster

2.1. Sürekli ücretsiz sürümü seçin

2.2. Kümenize bir ad verin

2.3. “Deploy”a tıklayın

2.4. Kullanıcı adınızı ve parolanızı güvenli bir yere kopyalayın

2.5. “Create database user”a tıklayın

2.6. Bağlantı yöntemi olarak “Drivers”ı seçin

“Drivers” for your connection method

2.7. Bir sonraki adım için bağlantı URI’sini kopyalayın

3.1. Kümeler görünümünde üç noktaya tıklayın

3.2. “Load sample dataset”i seçin

3.3. Listeden sample_analytics koleksiyonunu seçin ve yüklenmesini bekleyin.

Yerel MongoDB kurulumları için örnek veri kümelerini şu şekilde yükleyebilirsiniz:

# Download and restore the sample dataset
python -m pip install pymongo[srv]
python -c "from pymongo import MongoClient; MongoClient().admin.command('getParameter', '*')"
  • Veri boyutu: sample_analytics veri kümesi (~10MB) ücretsiz katmanda rahatça çalışacak kadar küçüktür
  • Koleksiyon yapısı: İlişki verileri içeren customers ve accounts koleksiyonlarını barındırır
  • Veri gerçekçiliği: Anlamlı aggregation örnekleri için gerçekçi finansal örüntülere dayanır

MongoDB’ye bağlanma

Artık MongoDB ve örnek veri kümesi hazır olduğuna göre, bağlanmak ve kurulumumuzu doğrulamak için kodu yazalım:

from pymongo.mongo_client import MongoClient
from pymongo.server_api import ServerApi

uri = "mongodb+srv://bex:[email protected]/?retryWrites=true&w=majority&appName=Cluster0"

# Create a new client and connect to the server
client = MongoClient(uri, server_api=ServerApi('1'))

# Send a ping to confirm a successful connection
try:
   client.admin.command('ping')
   print("Pinged your deployment. You successfully connected to MongoDB!")
except Exception as e:
   print(e)
Pinged your deployment. You successfully connected to MongoDB!
# Access the sample_analytics database
db = client.sample_analytics

# Verify connection by counting documents in collections
customer_count = db.customers.count_documents({})
account_count = db.accounts.count_documents({})

print(f"Found {customer_count} customers and {account_count} accounts in sample_analytics")

# Preview one document from each collection
print("\nSample customer document:")
print(db.customers.find_one())

print("\nSample account document:")
print(db.accounts.find_one())

Çıktı:

Found 500 customers and 1746 accounts in sample_analytics

Sample customer document:
{'_id': ObjectId('5ca4bbcea2dd94ee58162a68'), 'username': 'fmiller', 'name': 'Elizabeth Ray', 'address': '9286 Bethany Glens\nVasqueztown, CO 22939', 'birthdate': datetime.datetime(1977, 3, 2, 2, 20, 31), 'email': '[email protected]', 'active': True, 'accounts': [371138, 324287, 276528, 332179, 422649, 387979], 'tier_and_details': {'0df078f33aa74a2e9696e0520c1a828a': {'tier': 'Bronze', 'id': '0df078f33aa74a2e9696e0520c1a828a', 'active': True, 'benefits': ['sports tickets']}, '699456451cc24f028d2aa99d7534c219': {'tier': 'Bronze', 'benefits': ['24 hour dedicated line', 'concierge services'], 'active': True, 'id': '699456451cc24f028d2aa99d7534c219'}}}

Sample account document:
{'_id': ObjectId('5ca4bbc7a2dd94ee5816238c'), 'account_id': 371138, 'limit': 9000, 'products': ['Derivatives', 'InvestmentStock']}
  • Doğrulama: Kod, bağlantınızı ve veri kümesine erişiminizi teyit eder
  • Belge önizleme: Üzerinde çalışacağınız belgelerin yapısını gösterir

Bu kodu çalıştırdığınızda, belge sayımlarını ve hem müşteri hem hesap belgelerinden birer önizlemeyi gösteren çıktıyı görmelisiniz. Bu da ortamınızın, bir sonraki bölümlerde inceleyeceğimiz aggregation pipeline örnekleri için hazır olduğunu teyit eder.

PyMongo’ya ve yerel MongoDB kurulumuna giriş için başlangıç seviyesindeki PyMongo eğitimimize göz atın.

MongoDB Aggregation Pipeline’larına Derinlemesine Bakış

Bağlantımızı doğruladığımıza ve belge yapısını incelediğimize göre, şimdi MongoDB’nin aggregation çerçevesine dalalım. Bu güçlü özellik, veriyi doğrudan veritabanı içinde işlememize ve dönüştürmemize olanak tanır. Bu bölümde, örnek veri kümemizi kullanarak en yaygın pipeline aşamalarını pratik örneklerle keşfedeceğiz.

$match ile veriyi filtreleme

$match aşaması, belirtilen ölçütlere göre belgeleri filtreler. Daha karmaşık işlemlerden önce yalnızca ilgilendiğiniz veriye odaklanmanın bir yoludur.

9.000 $ üzeri limite sahip tüm birinci sınıf (premium) hesapları bulalım:

pipeline = [
   {"$match": {"limit": {"$gt": 9000}}}
]

premium_accounts = list(db.accounts.aggregate(pipeline))

print(f"Found {len(premium_accounts)} premium accounts")
print(premium_accounts[0])

Bu pipeline, hesapları filtrelemek için karşılaştırma operatörü $gt (büyüktür) ile $match aşamasını kullanır. find() yöntemi gibi çalışır ancak bir pipeline bağlamında. Sorgu, accounts koleksiyonundaki her belgeyi inceler ve limit alanı 9000’i aşanları tutar.

Çıktı:

Found 1701 premium accounts
{'_id': ObjectId('5ca4bbc7a2dd94ee5816238d'), 'account_id': 557378, 'limit': 10000, 'products': ['InvestmentStock', 'Commodity', 'Brokerage', 'CurrencyService']}

Sonuçlara baktığımızda, veritabanımızdaki toplam 1746 hesaptan 1701’inin premium olarak belirlendiğini görüyoruz. Bu filtreleme adımı odağımızı daraltır, böylece sonraki analizler daha verimli ve hedefli hale gelir. Kendi projelerinizde, bu tekniği aktif kullanıcılar, belirli bir tutarın üzerindeki işlemler veya belirli bir kategorideki ürünler üzerine odaklanmak ve ardından bu belgelere daha derinlemesine analiz uygulamak için kullanabilirsiniz.

$project, $sort, $limit ve $skip ile belgeleri yeniden şekillendirme

Bu aşamalar hangi alanların dahil edileceğini ve sonuçların nasıl düzenleneceğini kontrol etmenize yardımcı olur. İşte yalnızca gerekli bilgileri göstererek en yüksek limite sahip ilk 5 hesabı alan bir örnek:

pipeline = [
   {"$project": {
       "_id": 0,
       "account_id": 1,
       "limit": 1,
       "product_count": {"$size": "$products"}
   }},
   {"$sort": {"limit": -1}},
   {"$limit": 5}
]

top_accounts = list(db.accounts.aggregate(pipeline))
for account in top_accounts:
   print(account)

Bu pipeline birlikte çalışan üç aşamadan oluşur:

1. $project aşaması her belgeyi şu şekilde yeniden şekillendirir:

  • _id alanını hariç tutar (0 olarak ayarlar)
  • account_id ve limit alanlarını dahil eder (1 olarak ayarlar)
  • products dizisindeki öğeleri saymak için $size operatörünü (birçok aggregation pipeline operatöründen biri) kullanan product_count adlı yeni bir alan oluşturur

2. $sort aşaması sonuçları limit alanına göre azalan sırada (-1) düzenler

3. $limit aşaması, sıralamadan sonra yalnızca ilk 5 belgeyi tutar

Çıktı:

{'account_id': 674364, 'limit': 10000, 'product_count': 1}
{'account_id': 278603, 'limit': 10000, 'product_count': 2}
{'account_id': 383777, 'limit': 10000, 'product_count': 5}
{'account_id': 557378, 'limit': 10000, 'product_count': 4}
{'account_id': 198100, 'limit': 10000, 'product_count': 3}

Çıktı, en yüksek limite sahip beş hesabı gösteriyor; hepsinin limiti 10.000 $. Ayrıca, hesaplanan product_count alanı sayesinde her hesabın kaç ürün tuttuğunu görebiliyoruz. 

Bu, tüm alanları döndürmek yerine tam olarak gerekenlere odaklanan daha temiz bir veri sunumu sağlar. Kendi uygulamalarınız için panolar veya raporlar oluştururken, yalnızca en ilgili bilgileri sunmak, veri transferini azaltmak ve arayüzü sadeleştirmek için benzer teknikleri kullanabilirsiniz.

$group ile gruplama ve toplulaştırma

$group aşaması, toplulaştırmanın gerçekten parladığı yerdir. Belgeleri kategorize edebilir ve her grup için metrikler hesaplayabilirsiniz. Ürün türüne göre ortalama hesap limitini bulalım:

pipeline = [
   {"$unwind": "$products"},  # First unwind the products array
   {"$group": {
       "_id": "$products",
       "avg_limit": {"$avg": "$limit"},
       "count": {"$sum": 1}
   }},
   {"$sort": {"avg_limit": -1}}
]

product_analysis = list(db.accounts.aggregate(pipeline))
for product in product_analysis:
   print(f"Product: {product['_id']}")
   print(f"  Average limit: ${product['avg_limit']:.2f}")
   print(f"  Number of accounts: {product['count']}")

Bu pipeline, ürün verisini analiz etmek için birden çok operatör kullanır:

  1. $unwind operatörü, birden fazla ürünü olan belgeleri ayrı belgelere böler. Örneğin, ["Derivatives", "InvestmentStock"] ürünlerine sahip bir hesap, her ürün için birer belge olmak üzere iki belgeye dönüşür.
  2. $group aşaması ardından şunları yapar:
  • Ürün adına göre gruplar ($group içindeki _id alanı, gruplama anahtarını belirler)
  • Her ürün için ortalama limiti $avg toplayıcısını kullanarak hesaplar
  • Her ürün için hesap sayısını $sum: 1 kullanarak sayar (her belge için 1 ekler)

3. $sort aşaması, sonuçları ortalama limite göre azalan sırada düzenler

Çıktı:

Product: Commodity
 Average limit: $9963.89
 Number of accounts: 720
Product: Brokerage
 Average limit: $9960.86
 Number of accounts: 741
Product: InvestmentStock
 Average limit: $9955.90
 Number of accounts: 1746
Product: InvestmentFund
 Average limit: $9951.92
 Number of accounts: 728
Product: Derivatives
 Average limit: $9951.84
 Number of accounts: 706
Product: CurrencyService
 Average limit: $9946.09
 Number of accounts: 742

Sonuçlar, Commodity ürünlerinin en yüksek ortalama hesap limitleriyle ilişkili olduğunu, CurrencyService ürünlerinin ise en düşük ortalamaya sahip olduğunu ortaya koyuyor. 

Bu tür analizler, ürün teklifleri ile müşteri harcama kapasitesi arasındaki ilişkileri belirlemeye yardımcı olur. 

Kendi uygulamalarınızda, kategorilere göre satışları, özellik bazında kullanıcı etkileşimini veya modül bazında hataları analiz etmek—yani tek tek kayıtları incelemek yerine gruplar genelinde veriyi özetlemek—için benzer teknikleri kullanabilirsiniz.

$lookup ve $unwind ile koleksiyonları birleştirme

Verileriniz birden fazla koleksiyona yayıldığında, $lookup hepsini bir araya getirmenize yardımcı olur. Müşterileri ilişkili hesaplarıyla bulalım:

pipeline = [
   {"$match": {"username": "fmiller"}},  # Find a specific customer
   {"$lookup": {
       "from": "accounts",  # Collection to join with
       "localField": "accounts",  # Field from customers collection
       "foreignField": "account_id",  # Field from accounts collection
       "as": "account_details"  # Name for the new array field
   }},
   {"$project": {
       "name": 1,
       "accounts": 1,
       "account_details.account_id": 1,
       "account_details.limit": 1,
       "account_details.products": 1
   }}
]

customer_accounts = list(db.customers.aggregate(pipeline))

print(f"Customer: {customer_accounts[0]['name']}")
print(f"Has {len(customer_accounts[0]['account_details'])} accounts:")

for account in customer_accounts[0]['account_details']:
   print(f"  Account {account['account_id']}: ${account['limit']} limit with products: {', '.join(account['products'])}")

Bu pipeline, koleksiyonlar arası ilişkili veriyi nasıl birleştireceğinizi gösterir:

  1. $match aşaması kullanıcı adına göre belirli bir müşteriyi bulur
  2. $lookup aşaması, accounts koleksiyonu ile sol dış join gerçekleştirir:
  • from: hangi koleksiyonla birleştirileceğini belirtir
  • localField: mevcut koleksiyondaki (customers) eşleşecek alan
  • foreignField: hedef koleksiyondaki (accounts) eşleşecek alan
  • as: eşleşen belgeleri içerecek yeni dizi alanının adı

3. $project aşaması, yalnızca ilgili alanları gösterecek şekilde çıktıyı şekillendirir

Çıktı:

Customer: Elizabeth Ray
Has 6 accounts:
 Account 371138: $9000 limit with products: Derivatives, InvestmentStock
 Account 324287: $10000 limit with products: Commodity, CurrencyService, Derivatives, InvestmentStock
 Account 276528: $10000 limit with products: InvestmentFund, InvestmentStock
 Account 332179: $10000 limit with products: Commodity, CurrencyService, InvestmentFund, Brokerage, InvestmentStock
 Account 422649: $10000 limit with products: CurrencyService, InvestmentStock
 Account 387979: $10000 limit with products: Brokerage, Derivatives, InvestmentFund, Commodity, InvestmentStock

Çıktı, Elizabeth Ray’in finansal portföyüne kapsamlı bir bakış sunarak altı hesabının tamamını ve bu hesapların ilişkili ürünlerini tek bir sorgu sonucunda gösterir. 

Bu, birden çok sorgu veya istemci tarafı join gerektirmeden verilerinizin ilişkilerine 360 derece bir görünüm kazandırır. 

Kendi uygulamalarınızda, normalizasyon amacıyla veriyi koleksiyonlara böldüğünüz ancak analiz veya gösterim için tekrar bir araya getirmeniz gereken durumları düşünün. Yaygın örnekler arasında etkinlik geçmişi olan kullanıcı profilleri, stok durumu ile ürünler veya ilgili yorumları olan içerikler yer alır.

Karmaşık analizler için birden çok aşamayı birleştirme

Şimdi daha kapsamlı bir iş sorusunu ele alalım: “Müşteriler için, hizmet seviyelerine (tier) göre gruplanmış ortalama hesap limitleri nedir?” Bunun için müşteri belgelerimizdeki iç içe geçmiş bir nesneyi (tier_and_details) ele almamız ve ardından bu bilgiyi accounts koleksiyonuyla ilişkilendirmemiz gerekir.

Önce, customers koleksiyonunda çalıştığımız yapıyı anlamak için örnek bir müşteri için tier_and_details ve accounts alanlarını inceleyelim. tier_and_details alanı, her anahtarın bir seviye aboneliği tanımlayıcısı olduğu ve değerin seviye adı gibi ayrıntıları içerdiği bir nesnedir. accounts alanı, o müşteriyle ilişkili hesap kimliklerinin bir dizisidir.

# First, let's look at the structure of 'tier_and_details' again
sample_customer = db.customers.find_one({"username": "fmiller"}) # Using a known customer for consistency
print("Tier structure example for customer 'fmiller':")
print(sample_customer['tier_and_details'])
print(f"Customer 'fmiller' has account IDs: {sample_customer['accounts']}")

Çıktı:

Tier structure example for customer 'fmiller':
{'0df078f33aa74a2e9696e0520c1a828a': {'tier': 'Bronze', 'id': '0df078f33aa74a2e9696e0520c1a828a', 'active': True, 'benefits': ['sports tickets']}, '699456451cc24f028d2aa99d7534c219': {'tier': 'Bronze', 'benefits': ['24 hour dedicated line', 'concierge services'], 'active': True, 'id': '699456451cc24f028d2aa99d7534c219'}}
Customer 'fmiller' has account IDs: [371138, 324287, 276528, 332179, 422649, 387979]
pipeline = [
   # Step 1: Project necessary fields, including 'accounts' and convert 'tier_and_details'
   {"$project": {
       "tiers_array": {"$objectToArray": "$tier_and_details"}, # Convert object to array
       "customer_account_ids": "$accounts",  # Explicitly carry over the customer's account IDs
       "_id": 1  # Keep customer _id for later
   }},
   # Step 2: Unwind the new 'tiers_array' to process each tier object separately
   {"$unwind": "$tiers_array"},
   # Step 3: Reshape to clearly define the tier and keep customer account IDs
   {"$project": {
       "tier": "$tiers_array.v.tier",  # Extract the tier name
       "customer_account_ids": 1,  # Ensure account IDs are still present
       "customer_id": "$_id"  # Rename _id to customer_id for clarity
   }},
   # Step 4: Look up account details using the customer_account_ids
   {"$lookup": {
       "from": "accounts",  # Target collection
       "localField": "customer_account_ids",  # Array of account IDs from the customer
       "foreignField": "account_id",  # Field in the 'accounts' collection
       "as": "matched_account_details"  # New array with joined account documents
   }},
   # Step 5: Unwind the 'matched_account_details' array.
   {"$unwind": "$matched_account_details"},
   # Step 6: Group by tier to calculate statistics
   {"$group": {
       "_id": "$tier",  # Group by the tier name
       "avg_limit": {"$avg": "$matched_account_details.limit"}, # Calculate average limit
       "total_accounts_in_tier": {"$sum": 1},  # Count how many accounts fall into this tier
       "unique_customers_in_tier": {"$addToSet": "$customer_id"}  # Count unique customers in this tier
   }},
   # Step 7: Format the final output
   {"$project": {
       "tier_name": "$_id",  # Rename _id to tier_name
       "average_account_limit": "$avg_limit",
       "number_of_accounts": "$total_accounts_in_tier",
       "number_of_customers": {"$size": "$unique_customers_in_tier"},  # Get the count of unique customers
       "_id": 0  # Exclude the default _id
   }},
   # Step 8: Sort by average limit
   {"$sort": {"average_account_limit": -1}}
]

tier_analysis = list(db.customers.aggregate(pipeline))

print("\nTier Analysis Results:")

for tier_data in tier_analysis:
   print(f"Tier: {tier_data['tier_name']}")
   print(f"  Average Account Limit: ${tier_data['average_account_limit']:.2f}")
   print(f"  Number of Accounts in this Tier: {tier_data['number_of_accounts']}")
   print(f"  Number of Unique Customers in this Tier: {tier_data['number_of_customers']}")

Bu pipeline, karmaşık analizi sekiz yönetilebilir adıma böler:

  1. $project: tier_and_details nesnesini dönüştürerek başlarız. $objectToArray operatörü bu nesneyi anahtar-değer çiftlerinden oluşan bir diziye (tiers_array) çevirir. Bu önemlidir çünkü $unwind gibi aşamalar diziler üzerinde çalışır. Kritik olarak, müşteri belgesinden accounts dizisini customer_account_ids olarak ve müşterinin _id alanını da açıkça ileri taşırız.
  2. $unwind: Bu aşama tiers_array öğelerini parçalayarak, bir müşterinin her seviye girdisi için ayrı bir belge oluşturur. Her yeni belge hâlâ customer_account_ids ve özgün müşteri _id alanını içerir.
  3. $project: Belgeyi, iç içe geçmiş yapıdan ($tiers_array.v.tier) seviye adını (ör. "Bronze") net şekilde çıkarmak ve müşteri _id alanını açıklık için customer_id olarak yeniden adlandırmak üzere yeniden şekillendiririz. customer_account_ids ileri taşınır.
  4. $lookup: accounts koleksiyonuyla burada join yaparız. customer_account_ids (müşteri belgesindeki hesap numaraları dizisi) localField olarak kullanılır. foreignField, accounts koleksiyonundaki account_id alanıdır. MongoDB, account_id değeri customer_account_ids dizisinde bulunan tüm hesapları bularak bunları matched_account_details alanına bir dizi olarak ekler.
  5. $unwind: matched_account_details dizisini açarız. Böylece, bir müşteri-seviye birleşimi birden çok hesapla ilişkiliyse, o müşteri ve seviye ile ilişkili her bir hesap için ayrı bir belge elde ederiz.
  6. $group: Belgeleri seviyeye göre gruplarız. Her seviye için, birleştirilen hesap ayrıntılarındaki limit alanında $avg kullanarak avg_limiti hesaplarız; $sum: 1 ile total_accounts_in_tier değerini sayarız; ayrıca her seviye için benzersiz müşteri kimliklerini toplamak üzere $addToSeti customer_id ile kullanırız.
  7. $project: Çıktının son şeklini veririz. Gruplama aşamasından gelen ve seviye adını tutan _id’yi tier_name olarak yeniden adlandırırız. unique_customers_in_tier sayısını almak için $size kullanırız.
  8. $sort: Sonuçları average_account_limit alanına göre azalan sırada düzenleriz; böylece en yüksek ortalamaya sahip seviye önce görünür.
Tier Analysis Results:
Tier: Silver
 Average Account Limit: $9974.55
 Number of Accounts in this Tier: 393
 Number of Unique Customers in this Tier: 95
Tier: Bronze
 Average Account Limit: $9964.11
 Number of Accounts in this Tier: 418
 Number of Unique Customers in this Tier: 93
Tier: Platinum
 Average Account Limit: $9962.53
 Number of Accounts in this Tier: 427
 Number of Unique Customers in this Tier: 101
Tier: Gold
 Average Account Limit: $9962.44
 Number of Accounts in this Tier: 426
 Number of Unique Customers in this Tier: 99

Sonuçlar şimdi biraz farklı bir hiyerarşi gösteriyor: Ortalama olarak Silver seviye müşterileri en yüksek limitli hesaplara sahip, ardından Bronze, sonra Platinum ve son olarak Gold geliyor.

Bu tür içgörüler, müşteri segmentlerini anlamak açısından değerlidir. Örneğin, bir finans kuruluşu neden Silver ve Bronze seviyelerinin bu kadar yüksek ortalama limitlere sahip olduğunu araştırabilir veya pazarlama kampanyalarını uyarlayabilir ya da premium hizmetler sunabilir. 

$objectToArray kullanımı, iç içe geçmiş seviye verisini açmanın anahtarıydı ve customer_account_ids alanını dikkatle ileri taşımak, $lookup ile müşterileri kendi hesaplarına bağlayabilmemizi sağladı.

Kendi veri kümelerinizde toplulaştırmalarda kullanmanız gereken iç içe nesnelerle (ör. kullanıcı tercihleri, ürün öznitelikleri veya yapılandırma ayarları) karşılaştığınızda $objectToArray tekniğini hatırlayın. 

Özellikle $lookup işlemleri için sonraki aşamalarda gereken alanların $project aşamalarınıza açıkça dahil edildiğinden emin olun. Karmaşık veriyi bu şekilde yapılandırılmış adımlara bölmek, anlamlı içgörüleri doğrudan MongoDB içinde çıkarmanıza yardımcı olur.

İleri Düzey Pipeline Kalıpları

Sıralı dönüşümlerin ötesinde, MongoDB’nin aggregation çerçevesi, karmaşık analitik sorguları ele almak için sofistike kalıplar sunar. Veriyi aynı anda birden çok açıdan analiz etmeniz veya kayan bir belge kümesine dayalı hesaplamalar yapmanız gerektiğinde, bu ileri düzey kalıplar güçlü çözümleri doğrudan veritabanında sağlar.

$facet ile çok boyutlu analiz

$facet aşaması aynı girdi belge kümesini kullanarak tek bir aşama içinde birden çok toplulaştırma alt-pipeline’ını yürütmenize olanak tanır. Aynı ürün koleksiyonundan, ürünleri fiyat aralığına göre kategorize etmeniz ve eşzamanlı olarak en popüler 5 ürün markasını listelemeniz gerektiğini hayal edin. $facet bu farklı analitik bakış açılarını paralel olarak ele alır.

$facet içindeki her alt-pipeline, girdi belgeleri üzerinde bağımsız şekilde çalışır ve kendi çıktı belge dizisini üretir. Bu sayede—kapsamlı bir pano için gerekenler gibi—çeşitli metrikleri veya özetleri tek bir veritabanı sorgusunda toplayabilirsiniz. 

Örneğin, aynı kullanıcı veri setinden toplam aktif kullanıcı sayısını, abonelik seviyesine göre kullanıcı dağılımını ve son katılan kullanıcıların bir listesini eşzamanlı olarak alabilirsiniz. Bu, birden çok veritabanı çağrısının yükünü ortadan kaldırarak karmaşık görünümler için veri getirimi sürecini sadeleştirir ve zengin, çok yönlü raporlar oluşturmayı mümkün kılar.

Pencere fonksiyonlarıyla zamansal analiz

MongoDB 5.0 ile tanıtılan pencere fonksiyonları, “pencere” olarak bilinen ve mevcut belgeyle ilişkili bir belge kümesi üzerinde hesaplamalar yapar. 

Bu, zaman serisi verileri veya komşu belgelerden gelen bağlamın önemli olduğu herhangi bir sıralı veri kümesi için kullanışlıdır. Örneğin, 7 günlük hareketli satış ortalamasını hesaplamak veya her müşteri için zaman içinde kümülatif işlem toplamını bulmak isteyebilirsiniz.

Pencere fonksiyonları genellikle $setWindowFields aşaması içinde kullanılır. Bu aşama, bölümler (ör. ürün başına satışlar gibi belge grupları) ve bu bölümler içindeki sıralamayı (ör. tarihe göre) tanımlamanıza olanak tanır. 

Ardından, tanımlanmış bir pencere üzerinde (ör. önceki 3 belge ve mevcut belge) $avg, $sum, $min, $max ya da $derivative veya $integral gibi özel fonksiyonları uygulayabilirsiniz.

Örneğin, ürün satışlarının birikimli toplamını hesaplamayı düşünün. $setWindowFields kullanan bir pipeline şöyle görünebilir:

pipeline = [
   {"$match": {"category": "Electronics"}}, # Filter for electronics
   {"$sort": {"sale_date": 1}}, # Sort by sale date
   {"$setWindowFields": {
       "partitionBy": "$product_id", # Calculate running total per product
       "sortBy": {"sale_date": 1},
       "output": {
           "running_total_sales": {
               "$sum": "$sale_amount",
               "window": {
                   "documents": ["unbounded", "current"] # Sum from start to current document
               }
           }
       }
   }}
]
# electronics_sales_with_running_total = list(db.sales.aggregate(pipeline))

Bu kavramsal pipeline’da, her elektronik satış için bir running_total_sales alanı eklenir. Bu alan, o ürün için en eski satıştan mevcut satışa kadar olan sale_amount toplamını temsil eder. 

Daha önce karmaşık istemci tarafı mantık veya birden çok sorgu gerektiren bu tür hesaplamalar artık doğrudan veritabanında yapılabilir; bu da uygulama kodunu basitleştirir ve eğilim analizi veya dönemsel karşılaştırmalar için performansı iyileştirir. 

Sonuç

MongoDB aggregation pipeline’ları, veriyi doğrudan veritabanınız içinde işlemenin yapılandırılmış bir yöntemini sunar. Farklı işlem aşamalarını birbirine bağlayarak, kayıtları filtreleme, belgeleri yeniden şekillendirme, bilgiyi gruplama ve çeşitli koleksiyonlardan veriyi birleştirme gibi kapsamlı veri işlemlerini gerçekleştirebilirsiniz. 

Bu yaklaşım, PyMongo örneklerinde gösterildiği gibi büyük veri kümelerinden anlamı daha hızlı çıkarmanıza yardımcı olarak veri işleme iş akışlarınızı iyileştirir. Veriyi kaynağa yakın işlemek, analitik sorgular için sıklıkla daha iyi performans sağlar.

Aggregation pipeline’larda ustalaşmak, birçok veri analizi zorluğuna hazırlar. Öğrendiklerinizi uygulamak için, örneğin Perakende Veri Pipeline’ı Oluşturma gibi uygulamalı bir projeyi deneyebilirsiniz. 

Daha geniş bir veri sistemleri perspektifi ve MongoDB becerilerinin büyük resme nasıl oturduğu için, Python ile Veri Mühendisi yol haritası kapsamlı bir öğrenim sunar. Kariyerinizi ilerletmeyi düşünüyorsanız, yaygın MongoDB Mülakat Sorularını gözden geçirmek de tipik problem çözme beklentilerini anlamak açısından faydalı olabilir.

MongoDB aggregation pipeline SSS

MongoDB aggregation pipeline’ları nedir?

MongoDB aggregation pipeline’ları, veri analizi için bir çerçevedir. Belgeleri bir dizi aşamadan geçirerek dönüştürür ve hesaplanmış sonuçlar döndürürler.

Aggregation pipeline’lar veri işlemeyi nasıl iyileştirir?

Veriyi doğrudan MongoDB içinde karmaşık dönüşümlere ve analize tabi tutmanıza olanak tanırlar; bu da veri transferini azaltır ve veriyi kaynağa daha yakın işleyerek performansı artırır.

Bir MongoDB aggregation pipeline’ındaki yaygın aşamalar nelerdir?

Yaygın aşamalar arasında filtreleme için $match, belgeleri yeniden şekillendirmek için $project, veriyi toplulaştırmak için $group ve koleksiyonları birleştirmek için $lookup bulunur.

Python’u MongoDB aggregation pipeline’larıyla kullanabilir miyim?

Evet, bu eğitim MongoDB’nin resmi Python sürücüsü olan PyMongo kullanılarak aggregation pipeline’ların nasıl kurulup çalıştırılacağını göstermektedir.

Aggregation pipeline’larda aşama sırası neden önemlidir?

Aşama sırası performans açısından önemlidir. Veriyi $match ile erken filtrelemek, sonraki daha karmaşık aşamalar tarafından işlenen belge hacmini azaltır.

Bexruz (Bex) Tuychiev

Yazar

Bexruz (Bex) Tuychiev

2 yılı aşkın deneyime sahip bir veri bilimi içerik üreticisiyim ve Medium’da en büyük takipçi kitlelerinden birine sahibim. Yapay zekâ ve makine öğrenimi üzerine, biraz da alaycı bir üslupla yazılmış, ayrıntılı makaleler kaleme almayı seviyorum; çünkü onları biraz daha az sıkıcı hale getirmek için bir şeyler yapmak gerekiyor. 130’un üzerinde makale ve bir de DataCamp kursu ürettim; bir diğeri de hazırlık aşamasında. İçeriklerim 5 milyondan fazla kişi tarafından görüldü; bunların 20 bini Medium ve LinkedIn’de takipçim oldu. 

Konular

İlgili