Eksiksiz MongoDB Geliştirici Rehberi

4 Ağustos 2026 · netologist · 20 dakika, 4060 kelime ·

Özellikler, En İyi Uygulamalar ve Tasarım Kalıpları (Design Patterns)


İçindekiler

  1. Giriş ve Temel Kavramlar
  2. Veri Modelleme Temelleri
  3. Şema Tasarım Kalıpları
  4. CRUD İşlemleri
  5. İndeksleme Stratejileri
  6. Aggregation Framework (Toplulaştırma Çerçevesi)
  7. Transaction’lar (İşlemler)
  8. Replikasyon (Replication)
  9. Sharding (Parçalama)
  10. Performans Optimizasyonu
  11. Güvenlik En İyi Uygulamaları
  12. Change Streams ve Gerçek Zamanlı Uygulamalar
  13. Driver ve Uygulama Seviyesi En İyi Uygulamalar
  14. İzleme ve Operasyon
  15. Kaçınılması Gereken Anti-Pattern’ler
  16. Kontrol Listeleri

1. Giriş ve Temel Kavramlar

MongoDB, veriyi BSON (Binary JSON) dökümanları olarak saklayan doküman-tabanlı, dağıtık bir NoSQL veritabanıdır. Bu rehberdeki her şeyin temeli, temel yapı taşlarını anlamaktan geçer.

1.1 Temel Terminoloji

MongoDB Terimiİlişkisel Veritabanı Karşılığı
Database (Veritabanı)Database
Collection (Koleksiyon)Table (Tablo)
Document (Doküman)Row (Satır)
Field (Alan)Column (Sütun)
Index (İndeks)Index
Embedded Document (Gömülü Doküman)(Doğrudan karşılığı yok — iç içe join gibi düşünülebilir)
_idPrimary Key (Birincil Anahtar)

1.2 BSON vs JSON

BSON, JSON’u ek tiplerle genişletir: ObjectId, Date, Decimal128, Binary, Int32, Int64, Timestamp, Regex. Değerleri her zaman string olarak değil, BSON-native tipleriyle saklamayı tercih edin (örneğin tarihleri ISO string yerine Date tipiyle saklayın) — bu, doğru sıralama, aralık sorguları (range query) yapılmasını sağlar ve depolama alanını azaltır.

1.3 Doküman Modelinin Felsefesi

MongoDB’nin temel gücü, birlikte erişilen verinin birlikte saklanması gerektiği prensibidir. Bu, ilişkisel veritabanı normalizasyonundan kökten farklıdır. Modelleme sürecinde sorulması gereken asıl soru her zaman şudur:

“Uygulamam neyi sorguluyor ve bunu ne sıklıkla sorguluyor?”

Şu değil: “Bu verinin en normalize edilmiş hali nedir?”


2. Veri Modelleme Temelleri

2.1 Gömme (Embedding) vs Referans Verme (Referencing)

Bu, MongoDB şema tasarımındaki en önemli tek karardır.

Şu durumlarda gömün (embed):

Şu durumlarda referans verin (reference):

// Gömme örneği — yorumları olan bir blog yazısı (sınırlı, her zaman birlikte gösteriliyor)
{
  _id: ObjectId("..."),
  title: "MongoDB En İyi Uygulamaları",
  author: "Jane Doe",
  comments: [
    { user: "alice", text: "Harika yazı!", date: ISODate("2026-01-10") },
    { user: "bob",   text: "Çok faydalı", date: ISODate("2026-01-11") }
  ]
}

// Referans verme örneği — Müşteriye referans veren Siparişler (yeniden kullanılıyor, büyük koleksiyon)
{
  _id: ObjectId("..."),
  customerId: ObjectId("64f1a2..."),
  items: [ { sku: "A100", qty: 2, price: 19.99 } ],
  total: 39.98
}

2.2 16MB Doküman Limiti

Her BSON dokümanının 16MB’lık kesin bir sınırı vardır. Bu, modelleme kararlarını şekillendiren kritik bir kısıtlamadır — bir dizinin (array) veya gömülü yapının sınırsız büyüyebileceği bir şema asla tasarlamayın (örneğin bir kullanıcı dokümanına gömülü “bir kullanıcının tüm olayları” gibi).

2.3 Working Set ve RAM

MongoDB, working set (sık erişilen veri + indeksler) RAM’e sığdığında en iyi performansı gösterir. Dokümanlarınızı, sık erişilen alanları bir arada tutacak şekilde modelleyin ve nadiren kullanılan verilerle dokümanları şişirmekten kaçının (aşağıda anlatılan Extended Reference Pattern ile “sıcak” (hot) dokümanları yalın tutabilirsiniz).

2.4 Şema Versiyonlama

MongoDB şema esnekliğine sahip olduğundan, uygulamanız zamanla evrildikçe her zaman bir schemaVersion alanı ekleyin:

{ _id: ObjectId("..."), schemaVersion: 2, ... }

Bu, uygulamanın büyük bir tek seferlik (big-bang) migration yerine, dokümanları okuma/yazma sırasında tembel bir şekilde (lazily) migrate etmesine olanak tanır.


3. Şema Tasarım Kalıpları

MongoDB’nin resmi dokümantasyonu, kanıtlanmış bir dizi şema tasarım kalıbını (schema design pattern) kataloglar. Bunları isimleriyle bilmek, ekibinizle tasarım kararlarını net bir şekilde iletişim kurmanızı sağlar.

3.1 Attribute Pattern (Öznitelik Kalıbı)

Birçok benzer alanınız olduğunda ve bunlardan sadece bazıları herhangi bir dokümana uygulandığında, ayrıca bunlar arasında arama yapmanız gerektiğinde kullanılır.

// Şunun yerine: { color: "red", size: "M", material: "cotton", ... } (birçok opsiyonel alan)
{
  name: "T-Shirt",
  attributes: [
    { k: "color", v: "red" },
    { k: "size", v: "M" },
    { k: "material", v: "cotton" }
  ]
}
// İndeks: { "attributes.k": 1, "attributes.v": 1 }

3.2 Extended Reference Pattern (Genişletilmiş Referans Kalıbı)

Ekstra lookup işlemlerinden kaçınmak için, referans verilen bir dokümandan sık ihtiyaç duyulan birkaç alanı üst dokümana kopyalayın (kontrollü bir denormalizasyon).

// Sipariş dokümanı, "customers" koleksiyonuna join yapmadan görüntüleme için gereken alanları gömer
{
  orderId: "ORD-1001",
  customer: { id: ObjectId("..."), name: "Jane Doe", email: "[email protected]" }, // genişletilmiş referans
  items: [...]
}

3.3 Subset Pattern (Alt Küme Kalıbı)

Bir dokümanın büyük bir dizisi olduğunda (örneğin binlerce yorum) ama uygulama genelde sadece en son N tanesine ihtiyaç duyduğunda, küçük bir alt kümeyi gömülü tutun, geri kalanını ayrı bir koleksiyonda saklayın.

{
  productId: "P-100",
  name: "Kablosuz Fare",
  recentReviews: [ /* sadece son 10 yorum */ ]
}
// Tüm yorumlar, productId'ye referans veren ayrı bir "reviews" koleksiyonunda yaşar

3.4 Computed Pattern (Hesaplanmış Değer Kalıbı)

Hesaplanması pahalı olan değerleri (toplamlar, sayaçlar, ortalamalar) her okumada yeniden hesaplamak yerine önceden hesaplayıp saklayın. Bunları uygulama mantığı, trigger’lar veya zamanlanmış görevlerle güncelleyin.

{
  productId: "P-100",
  totalSold: 15234,      // hesaplanmış/önbelleklenmiş
  avgRating: 4.6,         // hesaplanmış/önbelleklenmiş
  reviewCount: 812
}

3.5 Bucket Pattern (Kova Kalıbı)

Zaman serisi veya akış verilerini, her okuma için bir doküman yerine “kovalara” (bucket) gruplayın (örneğin sensör başına saatlik bir doküman). Bu, doküman sayısını ve indeks yükünü ciddi şekilde azaltır.

{
  sensorId: "S-42",
  hour: ISODate("2026-08-17T09:00:00Z"),
  measurements: [
    { ts: ISODate("2026-08-17T09:00:12Z"), temp: 22.1 },
    { ts: ISODate("2026-08-17T09:00:27Z"), temp: 22.3 }
    // kova başına maksimum N adet
  ],
  count: 2,
  sum: 44.4
}

Not: Yoğun zaman serisi (time-series) iş yükleri için, elle yapılan bucketing yerine MongoDB’nin yerel Time Series Collections özelliğini tercih edin (db.createCollection("sensors", { timeseries: { timeField: "ts", metaField: "sensorId", granularity: "seconds" } })).

3.6 Outlier Pattern (Aykırı Değer Kalıbı)

Normal gömme varsayımlarınızı bozan nadir dokümanları (örneğin 50 milyon takipçisi olan bir ünlü hesabı) bir bayrak (flag) ekleyerek ve fazla veriyi sadece o aykırı değer için ayrı bir koleksiyona taşırarak yönetin.

{ userId: "u1", followers: [...], hasOverflow: false }
{ userId: "celebrity1", followers: [...1000 gösterilen...], hasOverflow: true }
// 1001. takipçiden itibaren "followers_overflow" koleksiyonunda yaşar

3.7 Polymorphic Pattern (Çok Biçimli Kalıp)

Farklı ama ilişkili “şekillere” sahip dokümanları, bir type alanıyla ayırt ederek aynı koleksiyonda saklayın — uygulamanın bunları birlikte sorguladığı durumlarda faydalıdır.

{ type: "car", make: "Toyota", doors: 4 }
{ type: "motorcycle", make: "Harley", hasSidecar: false }
// İkisi de "vehicles" koleksiyonunda

3.8 Ağaç / Hiyerarşi Kalıpları

Hiyerarşik veriler için (kategoriler, organizasyon şemaları, yorum ağaçları), erişim modeline göre seçim yapın:

// Ata Dizisi — hızlı "tüm ataları getir" ve "tüm alt öğeleri getir" sorguları
{
  _id: "electronics.laptops.gaming",
  name: "Oyun Laptopları",
  ancestors: ["electronics", "electronics.laptops"]
}

3.9 Approximation Pattern (Yaklaşıklık Kalıbı)

Mükemmel hassasiyetin gerekmediği analitikler için (örneğin sayfa görüntülenme sayaçları), sayacı olasılıksal olarak güncelleyerek (örneğin 100 yazımdan 1’inde, sonra 100 ile çarparak) yazma yükünü azaltın.

3.10 Şema Versiyonlama Kalıbı

§2.4’te ele alındı — migration’lar sırasında farklı şema versiyonlarının bir arada var olabilmesi için dokümanları her zaman bir versiyonla etiketleyin.

3.11 Single Collection Pattern (Tek Koleksiyon Kalıbı)

Her zaman birlikte sorgulanan ilişkili varlık tipleri, bir type ayırıcısıyla ayrılarak tek bir koleksiyonda yaşayabilir, bu da round-trip sayısını azaltır (polymorphic kalıba benzer, ancak tek bir koleksiyonda varlıklar arası sorgulara vurgu yapar — örneğin tek sorgulu mağaza sayfaları için product, category ve review tiplerini birlikte saklayan bir e-ticaret uygulaması).


4. CRUD İşlemleri

4.1 Ekleme (Insert)

db.users.insertOne({ name: "Jane", email: "[email protected]", createdAt: new Date() });

db.users.insertMany([
  { name: "Bob" },
  { name: "Alice" }
], { ordered: false }); // sırasız = tekil doküman hatalarında devam eder, genelde daha hızlıdır

4.2 Sorgu Temelleri

// Projection — sadece ihtiyacınız olan alanları projekte edin
db.users.find({ status: "active" }, { name: 1, email: 1, _id: 0 });

// Karşılaştırma operatörleri
db.orders.find({ total: { $gte: 100, $lt: 500 } });

// Mantıksal operatörler
db.orders.find({ $or: [ { status: "pending" }, { status: "processing" } ] });

// Dizi (array) sorguları
db.products.find({ tags: "sale" });               // dizi "sale" içeriyorsa eşleşir
db.products.find({ tags: { $all: ["sale", "new"] } });
db.products.find({ "reviews.rating": { $gte: 4 } }); // gömülü diziye dot notation ile erişim

// $elemMatch — birden fazla koşulun AYNI dizi elemanında eşleşmesi gerektiğinde
db.products.find({
  reviews: { $elemMatch: { rating: { $gte: 4 }, verified: true } }
});

4.3 Güncelleme (Update)

// Dokümanı tamamen değiştirmek yerine hedefli operatörleri tercih edin
db.users.updateOne(
  { _id: id },
  { $set: { status: "active" }, $currentDate: { updatedAt: true } }
);

// Artırma / dizi operatörleri
db.products.updateOne({ _id: id }, { $inc: { stock: -1 } });
db.posts.updateOne({ _id: id }, { $push: { comments: newComment } });
db.posts.updateOne({ _id: id }, { $push: { comments: { $each: [c1, c2], $slice: -50 } } }); // dizi boyutunu sınırla

// Upsert
db.counters.updateOne(
  { _id: "orderId" },
  { $inc: { seq: 1 } },
  { upsert: true }
);

// Bulk write — verimlilik için birden fazla işlemi toplu halde gönderme
db.orders.bulkWrite([
  { updateOne: { filter: { _id: 1 }, update: { $set: { status: "shipped" } } } },
  { updateOne: { filter: { _id: 2 }, update: { $set: { status: "shipped" } } } },
  { deleteOne: { filter: { _id: 3 } } }
], { ordered: false });

4.4 Silme (Delete)

db.sessions.deleteMany({ expiresAt: { $lt: new Date() } });

4.5 findAndModify Ailesi

// Atomik olarak getir-ve-güncelle — kuyruklar, sayaçlar, kilitler için harika
db.jobs.findOneAndUpdate(
  { status: "queued" },
  { $set: { status: "processing", startedAt: new Date() } },
  { sort: { priority: -1 }, returnDocument: "after" }
);

5. İndeksleme Stratejileri

İndeksler, sorgu performansı için en büyük tek etkendir. Eksik bir indeks, O(log n) bir aramayı O(n) bir koleksiyon taramasına (collection scan) dönüştürür.

5.1 İndeks Tipleri

TipKullanım Alanı
Tekli alan (Single field)Bir alan üzerinde basit eşitlik/aralık sorguları
Bileşik (Compound)Birden fazla alanda filtreleme/sıralama yapılan sorgular
MultikeyBir dizi alanı indekslendiğinde otomatik oluşturulur
TextTam metin arama (full-text search)
Geospatial (2dsphere)Konum tabanlı sorgular
HashedTek bir alanda sharding için eşit dağılım
WildcardBilinmeyen/dinamik alan isimleri
TTLDokümanları otomatik sona erdirme (session’lar, log’lar, önbellekler)
UniqueBenzersizlik kısıtlaması uygular
PartialSadece filtreye uyan dokümanların bir alt kümesini indeksler
Sparseİndekslenmiş alanı eksik olan dokümanları atlar

5.2 Bileşik İndeksler için ESR Kuralı

Bileşik indeksler oluştururken, alanları şu sırayla düzenleyin: Eşitlik (Equality) → Sıralama (Sort) → Aralık (Range).

// Sorgu: bir müşteri için aktif siparişleri bul, tarihe göre sırala, fiyat aralığında
db.orders.find({ customerId: id, status: "active", total: { $gt: 50 } })
          .sort({ createdAt: -1 });

// Optimal indeks: Eşitlik(customerId, status) -> Sıralama(createdAt) -> Aralık(total)
db.orders.createIndex({ customerId: 1, status: 1, createdAt: -1, total: 1 });

5.3 Covered Queries (Kapsanan Sorgular)

Bir sorgu, istenen tüm alanlar indeksin kendisinde mevcut olduğunda ve dokümanı hiç getirmeye gerek kalmadığında “covered” (kapsanmış) olur.

db.users.createIndex({ email: 1, name: 1 });
db.users.find({ email: "[email protected]" }, { email: 1, name: 1, _id: 0 }); // kapsanmış

5.4 Partial Index vs Sparse Index

Modern MongoDB’de sparse indeksler yerine partial indeksleri tercih edin — daha esnektirler.

// Sadece total > 0 olan aktif siparişleri indeksle — daha küçük, daha hızlı indeks
db.orders.createIndex(
  { customerId: 1 },
  { partialFilterExpression: { status: "active", total: { $gt: 0 } } }
);

5.5 TTL İndeksleri

db.sessions.createIndex({ lastAccess: 1 }, { expireAfterSeconds: 3600 });

5.6 İndeks Yönetimi En İyi Uygulamaları


6. Aggregation Framework (Toplulaştırma Çerçevesi)

Aggregation pipeline, MongoDB’nin karmaşık veri dönüşümü, analitik ve raporlama aracıdır.

6.1 Temel Aşamalar (Stages)

db.orders.aggregate([
  { $match: { status: "completed", createdAt: { $gte: ISODate("2026-01-01") } } }, // erken filtrele!
  { $group: {
      _id: "$customerId",
      totalSpent: { $sum: "$total" },
      orderCount: { $sum: 1 },
      avgOrder: { $avg: "$total" }
  }},
  { $sort: { totalSpent: -1 } },
  { $limit: 10 },
  { $lookup: {
      from: "customers",
      localField: "_id",
      foreignField: "_id",
      as: "customer"
  }},
  { $unwind: "$customer" },
  { $project: { _id: 0, customerName: "$customer.name", totalSpent: 1, orderCount: 1 } }
]);

6.2 Temel Aşama Referansı

AşamaAmaç
$matchDokümanları filtreler (mümkün olduğunca erken kullanın!)
$projectAlanları yeniden şekillendirir / dahil eder-hariç tutar
$groupDeğerleri (toplam, ortalama, sayaç vb.) anahtara göre toplulaştırır
$sortSonuçları sıralar
$limit / $skipSayfalama (büyük ölçekte $skip konusunda dikkatli olun — bkz. §10.5)
$lookupBaşka bir koleksiyona left-outer-join yapar
$unwindBir dizi alanını birden fazla dokümana açar
$addFields / $setYeni alanlar ekler veya hesaplar
$facetBirden fazla alt pipeline’ı paralel çalıştırır, örn. arama sonuçları + sayaçlar için
$bucket / $bucketAutoDokümanları aralıklara kategorize eder
$graphLookupHiyerarşik/grafik veriler için özyinelemeli (recursive) lookup
$merge / $outPipeline sonuçlarını bir koleksiyona yazar (materialized view’lar)
$replaceRootBir alt dokümanı üst seviyeye yükseltir
$setWindowFieldsPencere fonksiyonları (running total, sıralama) — MongoDB 5.0+

6.3 Aggregation Performans Kuralları

  1. $match ve $sort‘u mümkün olduğunca erken kullanın — pipeline’ın ilk aşamalarda indeksleri kullanabilmesini sağlar.
  2. $project‘i erken kullanarak sonraki aşamalara akan doküman boyutunu azaltın (alanlara daha sonra ihtiyaç duyulmadığı sürece).
  3. Büyük, indekssiz foreign koleksiyonlarda $lookup‘tan kaçının — her zaman foreignField‘i indeksleyin.
  4. Aşama başına 100MB bellek limitini aşabilecek büyük aggregation’lar için allowDiskUse: true kullanın.
  5. “Veri + sayaç” sorgularını tek bir round-trip’te birleştirmek için $facet kullanın.
  6. Pahalı, tekrarlayan aggregation’ları $merge ile önceden hesaplanmış bir koleksiyona materialize edin (Computed Pattern’in bir biçimi).

6.4 Pencere Fonksiyonu Örneği (MongoDB 5.0+)

db.sales.aggregate([
  { $setWindowFields: {
      partitionBy: "$region",
      sortBy: { date: 1 },
      output: {
        runningTotal: { $sum: "$amount", window: { documents: ["unbounded", "current"] } },
        rank: { $rank: {} }
      }
  }}
]);

7. Transaction’lar (İşlemler)

MongoDB, v4.0’dan itibaren (replica set’lerde) ve v4.2’den itibaren (sharded cluster’larda) çok-dokümanlı ACID transaction’ları destekler.

7.1 Ne Zaman İhtiyaç Duyarsınız

Gömme (embedding) sayesinde, MongoDB’nin her zaman garanti ettiği tek-doküman atomikliği çoğu kullanım senaryosunu kapsar. Çok-dokümanlı transaction’lara sadece birden fazla koleksiyondaki birden fazla dokümanı atomik olarak güncellemeniz gerektiğinde başvurun — örneğin bir banka transferi (bir hesaptan düş, diğerine ekle).

const session = client.startSession();
try {
  session.startTransaction({
    readConcern: { level: "snapshot" },
    writeConcern: { w: "majority" }
  });

  await accounts.updateOne({ _id: fromId }, { $inc: { balance: -amount } }, { session });
  await accounts.updateOne({ _id: toId }, { $inc: { balance: amount } }, { session });

  await session.commitTransaction();
} catch (err) {
  await session.abortTransaction();
  throw err;
} finally {
  session.endSession();
}

7.2 Transaction En İyi Uygulamaları


8. Replikasyon (Replication)

Bir Replica Set, yüksek erişilebilirlik ve okuma ölçeklendirmesi sağlayarak aynı veri kümesini koruyan bir grup mongod sürecidir.

8.1 Topoloji

Önerilen minimum: 3 veri tutan node (temiz bir seçim çoğunluğu için tek sayı).

8.2 Write ve Read Concern

// Write Concern — bir yazmanın onaylanması için kaç node gerektiği
db.orders.insertOne(doc, { writeConcern: { w: "majority", wtimeout: 5000 } });

// Read Concern — okumalar için tutarlılık garantisi
db.orders.find().readConcern("majority");

// Read Preference — hangi member'lardan okunacağı
db.orders.find().readPref("secondaryPreferred");
Read PreferenceDavranış
primary (varsayılan)Her zaman primary’den okur — en güçlü tutarlılık
primaryPreferredMümkünse primary, değilse secondary
secondaryHer zaman bir secondary’den okur
secondaryPreferredMümkünse secondary, değilse primary
nearestEn düşük ağ gecikmesine sahip member

Dikkat: Secondary’lerden okumak replikasyon gecikmesi / eski (stale) veri okuma riski taşır. Sadece analitik, raporlama veya nihai tutarlılığın (eventual consistency) kabul edilebilir olduğu kullanım senaryolarında kullanın.

8.3 En İyi Uygulamalar


9. Sharding (Parçalama)

Sharding, tek bir replica set’in veri hacmini veya throughput’u artık kaldıramadığı durumlarda, veriyi birden fazla makineye (shard) dağıtan MongoDB’nin yatay ölçeklendirme mekanizmasıdır.

9.1 Temel Bileşenler

9.2 Shard Key Seçimi — En Önemli Karar

İyi bir shard key şu özelliklere sahiptir:

  1. Yüksek kardinalite (cardinality) — çok sayıda farklı değer.
  2. Eşit dağılım — sıcak (hot) shard’lardan kaçınır.
  3. Sorgu izolasyonu — idealde, çoğu sorgu shard key’i içerir, böylece mongos tüm shard’lara yayın yapmak (“scatter-gather”) yerine tek bir shard’ı hedefleyebilir.
sh.shardCollection("app.orders", { customerId: "hashed" }); // hashed = eşit dağılım
// veya iyi izolasyona sahip aralık tabanlı sorgular için bileşik bir shard key:
sh.shardCollection("app.events", { tenantId: 1, createdAt: 1 });

9.3 Yaygın Shard Key Anti-Pattern’leri

Çözüm: bir hashed shard key kullanın, veya düşük kardinaliteli bir öneki (prefix) yüksek kardinaliteli, monoton olmayan bir sonek (suffix) ile birleştiren bir bileşik anahtar kullanın (bu, resmi “Hashed Shard Key” ve “Compound Shard Key” kalıplarının özüdür).

9.4 Zone’lar (Tag-Aware Sharding)

Belirli veri aralıklarını belirli shard’lara yönlendirin — yaygın olarak coğrafi tabanlı veri yerleşimi (data residency) gereksinimleri için kullanılır (örneğin AB kullanıcı verisinin AB’de bulunan shard’larda yaşaması gerektiğinde).


10. Performans Optimizasyonu

10.1 explain()‘i Dini Bir Görev Gibi Kullanın

db.orders.find({ status: "shipped" }).explain("executionStats");

COLLSCAN‘e (kötü — tam koleksiyon taraması) karşı IXSCAN‘e (iyi — indeks kullanılıyor) bakın. totalDocsExamined ile nReturned‘i karşılaştırın — birbirlerine yakın olmalılar.

10.2 Büyük Skip Değerlerinden Kaçının

Sayfalama için $skip kullanmak, büyük ölçekte yavaşlar çünkü MongoDB atlanan tüm dokümanların üzerinden geçmek zorunda kalır.

// Büyük ölçekte KÖTÜ:
db.posts.find().sort({ _id: -1 }).skip(100000).limit(20);

// İYİ — aralık tabanlı (keyset) sayfalama:
db.posts.find({ _id: { $lt: lastSeenId } }).sort({ _id: -1 }).limit(20);

10.3 Projection Disiplini

Sadece 2 alana ihtiyacınız varsa asla tam bir dokümanı find() etmeyin — ağ transferini ve bellek baskısını azaltır.

10.4 Connection Pooling (Bağlantı Havuzlama)

Uygulama süreci başına tek bir MongoClient örneği yeniden kullanın; driver’lar dahili olarak bir bağlantı havuzu yönetir. İstek başına yeni bir client oluşturmayın.

10.5 $where ve Ağır JavaScript’ten Kaçının

$where ve mapReduce, sunucu tarafında JavaScript çalıştırır ve indeksleri verimli bir şekilde kullanamaz — bunun yerine aggregation pipeline operatörlerini tercih edin.

10.6 Toplu (Batch) Okuma ve Yazma

Round-trip sayısını azaltmak için bulkWrite, cursor batching (batchSize()) ve insertMany kullanın.

10.7 Şema Doğrulama (Schema Validation)

Esneklikten ödün vermeden hatalı veriyi erken yakalamak için koleksiyon seviyesinde JSON Schema doğrulaması kullanın:

db.createCollection("orders", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["customerId", "total", "status"],
      properties: {
        total: { bsonType: "decimal", minimum: 0 },
        status: { enum: ["pending", "shipped", "delivered", "cancelled"] }
      }
    }
  },
  validationLevel: "moderate" // migration sırasında mevcut dokümanları bozma
});

11. Güvenlik En İyi Uygulamaları

  1. Kimlik Doğrulama ve Yetkilendirmeyi Etkinleştirin (--auth) — production’ı asla bunlar olmadan çalıştırmayın.
  2. Rol Tabanlı Erişim Kontrolü (RBAC) — uygulama kullanıcıları için readWriteAnyDatabase/root yerine en az ayrıcalık ilkesiyle özel roller tanımlayın.
  3. Transit sırasında şifreleme — tüm client-server ve cluster içi trafik için TLS/SSL’i etkinleştirin.
  4. Bekleme sırasında (at rest) şifreleme — WiredTiger şifreli storage engine’i veya disk seviyesi şifreleme kullanın.
  5. Ağ izolasyonu — özel IP’lere bağlanın, güvenlik duvarları/VPC güvenlik gruplarını kullanın, MongoDB’yi asla doğrudan public internete açmayın (0.0.0.0/0 bind’i klasik bir ihlal vektörüdür).
  6. Yüksek hassasiyetli alanlar (PII, ödeme verisi) için Field-Level / Client-Side Field Level Encryption (CSFLE) — veri, uygulamadan çıkmadan önce şifrelenir.
  7. Audit logging (denetim günlüğü) — hassas koleksiyonlara erişimi izleyin (Enterprise/Atlas özelliği).
  8. Kimlik bilgilerini düzenli olarak rotate edin, secret manager’lar kullanın (bağlantı string’lerine asla parola hardcode etmeyin).
  9. Tüm kullanıcı girdilerini doğrulayın ve temizleyin — MongoDB SQL injection’a karşı savunmasız olmasa da, ham kullanıcı JSON’unu doğrudan sorgulara geçirirseniz NoSQL/operatör injection‘a karşı savunmasızdır.
// SAVUNMASIZ — kullanıcı girdisi doğrudan bir operatör olarak kullanılıyor
db.users.find({ password: req.body.password }); // eğer body.password = {"$ne": null} => atlatma!

// GÜVENLİ — sorgulamadan önce tipleri doğrulayın
if (typeof req.body.password !== "string") throw new Error("Geçersiz girdi");

12. Change Streams ve Gerçek Zamanlı Uygulamalar

Change stream’ler, uygulamaların polling yapmadan gerçek zamanlı veri değişikliklerine abone olmasını sağlar.

const changeStream = db.collection("orders").watch([
  { $match: { operationType: { $in: ["insert", "update"] } } }
]);

changeStream.on("change", (change) => {
  console.log("Sipariş değişti:", change.documentKey, change.updateDescription);
});

Kullanım senaryoları: önbellek geçersiz kılma (cache invalidation), bildirim tetikleme, arama motorlarına senkronizasyon (Elasticsearch/Atlas Search), mikroservis olay hatları (outbox’sız CDC).

En iyi uygulamalar:


13. Driver ve Uygulama Seviyesi En İyi Uygulamalar

  1. Uygulama başına bir MongoClient — thread-safe’tir ve havuzlamayı yönetir; istek başına yeniden örneklemekten kaçının.
  2. Her zaman makul timeout’lar ayarlayın (serverSelectionTimeoutMS, connectTimeoutMS, socketTimeoutMS) — takılıp kalmak yerine hızlıca başarısız olun.
  3. Resmi driver’ları kullanın ve güncel tutun — sunucu yeteneklerini ve protokol değişikliklerini takip ederler.
  4. Idempotent yazmaları yeniden deneyin — geçici ağ kesintilerini otomatik olarak ele almak için retryWrites=true‘yu etkinleştirin (modern driver’larda varsayılandır).
  5. Bir ODM/ORM’i bilinçli olarak kullanın (Node için Mongoose, Python async için Motor, Java için Spring Data MongoDB) — şema doğrulama ve lifecycle hook’ları ekler, ama arka planda ürettikleri sorguları anlayın.
  6. Cursor’ları düzgün bir şekilde kapatın ve büyük sonuç kümelerini belleğe yüklemekten kaçının — sınırsız sorgularda .toArray() yerine streaming/cursor iterasyonu kullanın.
  7. Ortama özel bağlantı string’leri — kaynak koduna asla kimlik bilgileri içeren mongodb:// URI’lerini hardcode etmeyin; ortam değişkenleri veya bir secret manager kullanın.

14. İzleme ve Operasyon


15. Kaçınılması Gereken Anti-Pattern’ler

Anti-PatternNeden KötüÇözüm
Bir dokümanda sınırsız dizi16MB limitine çarpar, ondan çok önce performans düşerSubset Pattern / ayrı koleksiyon
Aşırı sayıda koleksiyon (kullanıcı/tenant başına bir tane)Meta veri ve depolama yükü, yönetimi zorTenant/ayırıcı alanlı tek koleksiyon
Derin iç içe geçmiş dokümanlar (>3-4 seviye)Sorgulaması/indekslemesi zor, garip güncellemelerDüzleştirin veya referans verin
İş mantığı için $where/JS kullanmaYavaş, indeksleri kullanamazAggregation pipeline
Sık filtrelenen/sıralanan alanlarda indeks olmamasıTam koleksiyon taramalarıUygun bileşik indeksler ekleyin
Dokümanlarda büyük binary blob saklama (resim/video)Working set’i şişirir, sorguları yavaşlatırGridFS veya harici nesne depolama (S3) + URL’yi saklayın
Kritik yazmalarda write concern’i göz ardı etmeFailover sırasında sessiz veri kaybıw: "majority"
MongoDB’yi ilişkisel bir veritabanı gibi ele alma (aşırı normalizasyon)Fazla $lookup, kötü performansErişim kalıplarına göre gömün
Büyük ölçekte skip tabanlı sayfalamaSayfa başına O(n) maliyetiAralık/keyset tabanlı sayfalama
Geçici transaction hatalarını ele almamaGeçici kesintilerde uygulama seviyesi hatalarDriver’ın sağladığı hata etiketleriyle yeniden deneyin

16. Kontrol Listeleri

16.1 Yeni Koleksiyon Kontrol Listesi

16.2 Production Öncesi Kontrol Listesi

16.3 Ölçeklendirme Kontrol Listesi (Sharding Öncesi)


Bu rehber, MongoDB geliştirmenin pratik özünü kapsamaktadır. Belirli alanlarda derinlemesine bilgi için (Atlas Search, Vector Search, Time Series Collections, Client-Side Field Level Encryption iç yapısı), özellikler ve en iyi uygulamalar sürekli geliştiği için resmi MongoDB dokümantasyonuna başvurun.