Skip to content

📌 Ne Zaman Kullanılır?

  • ✅ Esnek schema, hızlı prototip, real-time, IoT, CMS, log toplama
  • ⚠️ İlişkisel veri için SQL daha iyi (JOIN yoğun sorgular)
  • ❌ Transaction-ağırlıklı iş (banka, finans), karmaşık ilişkisel veri

Önerilen Kullanım: Node.js + Mongoose + MongoDB (esnek veri modeli) Alternatifler: PostgreSQL (JSONB ile esnek), DynamoDB (AWS), Firebase Firestore

MongoDB

NoSQL Nedir? Ne Zaman Kullanılır? (What is NoSQL & When to Use?)

NoSQL (Not Only SQL): Esnek şema, yapılandırılmamış/yarı yapılandırılmış veri depolama.

Kullanım alanları / Use cases:

  • Hızlı değişen veri yapıları (startup MVP, prototip)
  • Real-time analytics, log toplama
  • IoT sensor verileri
  • İçerik yönetim sistemleri (CMS)
  • Sosyal medya uygulamaları (kullanıcı profilleri, yorumlar)

Kurulum (Installation)

Ubuntu

bash
# MongoDB 7.0 GPG key ve repo ekle
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \
  sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor

echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] \
  https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | \
  sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list

sudo apt update
sudo apt install mongodb-org -y
sudo systemctl start mongod
sudo systemctl enable mongod

Docker

bash
docker run -d \
  --name mongo-dev \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=secret123 \
  -p 27017:27017 \
  mongo:7

# mongosh ile baglan / Connect with mongosh
docker exec -it mongo-dev mongosh -u admin -p secret123

mongosh CLI Komutları (CLI Commands)

javascript
// Veritabani islemleri / Database operations
show dbs                         // Veritabanlarini listele
use myapp                        // Veritabanina gec (yoksa olusturur)
db.dropDatabase()                // Veritabanini sil

// Koleksiyon islemleri / Collection operations
show collections                 // Koleksiyonlari listele
db.createCollection("users")     // Koleksiyon olustur
db.users.drop()                  // Koleksiyonu sil

// Yardimci / Helpers
db.stats()                       // Veritabani istatistikleri
db.users.countDocuments()        // Dokuman sayisi
db.users.estimatedDocumentCount() // Tahmini sayi (hizli)

CRUD İşlemleri (CRUD Operations)

javascript
// INSERT
db.users.insertOne({
    name: "Ali Yilmaz",
    email: "ali@test.com",
    age: 28,
    tags: ["admin", "editor"],
    address: { city: "Istanbul", country: "TR" },
    createdAt: new Date()
});

db.users.insertMany([
    { name: "Ayse Demir", email: "ayse@test.com", age: 32, tags: ["user"] },
    { name: "Mehmet Kaya", email: "mehmet@test.com", age: 25, tags: ["user", "editor"] }
]);

// FIND (SELECT)
db.users.find();                                    // Tum dokumanlar
db.users.find({ age: { $gt: 25 } });               // age > 25
db.users.find({ tags: "admin" });                   // tags icinde "admin"
db.users.find({ "address.city": "Istanbul" });      // Nested field
db.users.findOne({ email: "ali@test.com" });        // Tek dokuman

// Projeksiyon / Projection (belirli alanlar)
db.users.find({ age: { $gt: 20 } }, { name: 1, email: 1, _id: 0 });

// Siralama, limit, skip / Sort, limit, skip
db.users.find().sort({ age: -1 }).limit(10).skip(20);

// UPDATE
db.users.updateOne(
    { email: "ali@test.com" },
    { $set: { age: 29, "address.city": "Ankara" } }
);

db.users.updateMany(
    { age: { $lt: 30 } },
    { $set: { status: "young" }, $inc: { loginCount: 1 } }
);

// DELETE
db.users.deleteOne({ email: "mehmet@test.com" });
db.users.deleteMany({ status: "inactive" });

Query Operators

javascript
// Karsilastirma / Comparison
db.users.find({ age: { $gt: 25 } });      // greater than
db.users.find({ age: { $gte: 25 } });     // greater than or equal
db.users.find({ age: { $lt: 30 } });      // less than
db.users.find({ age: { $lte: 30 } });     // less than or equal
db.users.find({ age: { $ne: 25 } });      // not equal
db.users.find({ age: { $in: [25, 28, 32] } });   // in list
db.users.find({ age: { $nin: [25, 28] } });       // not in list

// Mantiksal / Logical
db.users.find({ $and: [{ age: { $gt: 20 } }, { age: { $lt: 30 } }] });
db.users.find({ $or: [{ city: "Istanbul" }, { city: "Ankara" }] });
db.users.find({ age: { $not: { $gt: 30 } } });

// Regex
db.users.find({ name: { $regex: /^ali/i } });
db.users.find({ email: { $regex: "test\\.com$" } });

// Element / Varlik
db.users.find({ phone: { $exists: true } });
db.users.find({ age: { $type: "int" } });

Aggregation Pipeline

javascript
// Basit gruplama / Simple grouping
db.orders.aggregate([
    { $match: { status: "completed" } },
    { $group: {
        _id: "$userId",
        totalSpent: { $sum: "$total" },
        orderCount: { $sum: 1 },
        avgOrder: { $avg: "$total" }
    }},
    { $sort: { totalSpent: -1 } },
    { $limit: 10 }
]);

// Lookup (SQL JOIN benzeri / SQL JOIN equivalent)
db.orders.aggregate([
    { $lookup: {
        from: "users",
        localField: "userId",
        foreignField: "_id",
        as: "user"
    }},
    { $unwind: "$user" },
    { $project: {
        _id: 0,
        orderId: "$_id",
        total: 1,
        userName: "$user.name",
        userEmail: "$user.email"
    }}
]);

// Tarih bazli gruplama / Date-based grouping
db.orders.aggregate([
    { $group: {
        _id: {
            year: { $year: "$createdAt" },
            month: { $month: "$createdAt" }
        },
        revenue: { $sum: "$total" },
        count: { $sum: 1 }
    }},
    { $sort: { "_id.year": 1, "_id.month": 1 } }
]);

$unwind -- Array Açma (Array Unwinding)

javascript
// { _id: 1, name: "Ali", scores: [85, 92, 78] }
// $unwind sonrasi: 3 ayri dokuman (scores: 85), (scores: 92), (scores: 78)
db.students.aggregate([
    { $unwind: "$scores" },
    { $group: { _id: "$name", avgScore: { $avg: "$scores" } } }
]);

// Bos array'leri koruma
db.orders.aggregate([
    { $unwind: { path: "$items", preserveNullAndEmptyArrays: true } }
]);

$facet -- Çoklu Pipeline (Multiple Pipelines)

Tek sorgu içinde birden fazla aggregation pipeline çalıştırır.

javascript
db.products.aggregate([
    { $facet: {
        priceStats: [
            { $group: { _id: null, avg: { $avg: "$price" }, min: { $min: "$price" }, max: { $max: "$price" } } }
        ],
        byCategory: [
            { $group: { _id: "$category", count: { $sum: 1 } } },
            { $sort: { count: -1 } }
        ],
        topExpensive: [
            { $sort: { price: -1 } }, { $limit: 5 }, { $project: { name: 1, price: 1 } }
        ]
    }}
]);

$bucket / $bucketAuto -- Aralık Gruplama (Range Grouping)

javascript
// Manuel aralik
db.users.aggregate([
    { $bucket: {
        groupBy: "$age",
        boundaries: [0, 18, 30, 45, 60, 120],
        default: "Diger",
        output: { count: { $sum: 1 } }
    }}
]);

// Otomatik esit dagilim
db.orders.aggregate([
    { $bucketAuto: { groupBy: "$total", buckets: 4, output: { count: { $sum: 1 } } } }
]);

$addFields / $set ve $merge

javascript
// Alan ekleme / guncelleme ($addFields ve $set ayni islevi gorur)
db.orders.aggregate([
    { $addFields: {
        totalWithTax: { $multiply: ["$total", 1.18] },
        itemCount: { $size: "$items" }
    }}
]);

// Sonucu baska koleksiyona yaz (ETL / materialize view)
db.orders.aggregate([
    { $match: { status: "completed" } },
    { $group: {
        _id: { year: { $year: "$createdAt" }, month: { $month: "$createdAt" } },
        totalRevenue: { $sum: "$total" },
        orderCount: { $sum: 1 }
    }},
    { $merge: { into: "monthly_reports", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
]);

Aggregation Performans (Aggregation Performance)

javascript
// 1. $match ve $project pipeline'in basina koy (index kullanimi)
// 2. Buyuk veri setlerinde allowDiskUse
db.orders.aggregate([...], { allowDiskUse: true });
// 3. explain() ile analiz
db.orders.explain("executionStats").aggregate([...]);

Multi-document Transactions

MongoDB 4.0+ sürümlerinde multi-document transaction desteği bulunur. Replica set gerektirir.

mongosh ile Transaction

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

try {
    const accounts = session.getDatabase("bank").accounts;
    accounts.updateOne({ name: "Ali", balance: { $gte: 500 } }, { $inc: { balance: -500 } }, { session });
    accounts.updateOne({ name: "Ayse" }, { $inc: { balance: 500 } }, { session });
    session.commitTransaction();
} catch (error) {
    session.abortTransaction();
} finally {
    session.endSession();
}

Node.js ile Transaction

javascript
const session = await mongoose.startSession();
try {
    await session.withTransaction(async () => {
        const product = await Product.findOneAndUpdate(
            { _id: productId, stock: { $gte: quantity } },
            { $inc: { stock: -quantity } },
            { session, new: true }
        );
        if (!product) throw new Error("Yetersiz stok");
        await Order.create([{ userId, productId, quantity, total: product.price * quantity }], { session });
    });
} finally {
    session.endSession();
}

writeConcern ve readConcern

SeviyeAçıklama
readConcern: "local"Varsayılan. Yerel node'dan oku (rollback riski)
readConcern: "majority"Çoğunluk tarafından onaylanan veriyi oku
readConcern: "snapshot"Transaction boyunca tutarlı snapshot
writeConcern: { w: "majority" }Çoğunluk node'a yazıldı
writeConcern: { w: "majority", j: true }Çoğunluk + journal'a yazıldı

Transaction Best Practices

  • Kısa tut: 60 saniyeyi geçmemeli, uzun işlemler lock'a neden olur
  • Retry logic: TransientTransactionError için otomatik tekrar mekanizması kur
  • Gereksiz yere kullanma: Tek doküman işlemleri zaten atomiktir
  • Replica set gerektirir: Standalone'da çalışmaz (test için single-node replica set kur)

İndeks (Indexes)

javascript
// Tekli indeks / Single field index
db.users.createIndex({ email: 1 });         // 1 = ascending, -1 = descending

// Benzersiz indeks / Unique index
db.users.createIndex({ email: 1 }, { unique: true });

// Bilesik indeks / Compound index
db.orders.createIndex({ userId: 1, createdAt: -1 });

// Text index (full-text search)
db.products.createIndex({ name: "text", description: "text" });
db.products.find({ $text: { $search: "hydraulic press" } });

// TTL index (otomatik silme / auto-delete)
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 });

// Indeksleri goster / List indexes
db.users.getIndexes();

// Indeks sil / Drop index
db.users.dropIndex("email_1");

Compound Index Sırası -- ESR Kuralı (ESR Rule)

Compound index alan sırası performansı doğrudan etkiler:

  1. Equality: Eşitlik koşulları ilk sıraya (status: "active")
  2. Sort: Sıralama alanları ikinci sıraya (createdAt: -1)
  3. Range: Aralık sorguları son sıraya (age: { $gt: 25 })
javascript
// Sorgu: status = "active", age > 25, createdAt'e gore sirala
db.users.find({ status: "active", age: { $gt: 25 } }).sort({ createdAt: -1 });

// Dogru (ESR):  { status: 1, createdAt: -1, age: 1 }
// Yanlis:       { age: 1, status: 1, createdAt: -1 }  // range once = sort icin index kullanilamaz

Partial Index

javascript
// Sadece aktif kullanicilar icin index (index boyutunu kucultur)
db.users.createIndex(
    { email: 1 },
    { unique: true, partialFilterExpression: { isActive: true } }
);
// Not: Sorgu partial filter'a uymazsa index kullanilmaz

Wildcard Index

javascript
// Schemaless alanlar icin (metadata gibi)
db.products.createIndex({ "metadata.$**": 1 });

// Tum alanlari indexle (dikkatli kullan)
db.logs.createIndex({ "$**": 1 });

Hashed Index

javascript
// Esitlik sorgulari ve shard key icin (range desteklemez)
db.users.createIndex({ email: "hashed" });
sh.shardCollection("myapp.users", { email: "hashed" });

İndeks Kullanım Analizi -- explain() (Index Usage Analysis)

javascript
db.users.find({ email: "ali@test.com" }).explain("executionStats");
// IXSCAN = index kullaniliyor, COLLSCAN = full scan (kotuye isaret)
// totalDocsExamined >> nReturned ise index verimli degil

// Tum indexlerin kullanim istatistikleri
db.users.aggregate([{ $indexStats: {} }]);

Schema Validation

MongoDB 3.6+ ile koleksiyonlara schema validation kuralları eklenebilir.

$jsonSchema ile Validation

javascript
db.createCollection("users", {
    validator: {
        $jsonSchema: {
            bsonType: "object",
            required: ["name", "email", "age"],
            properties: {
                name: { bsonType: "string", minLength: 2, maxLength: 100 },
                email: { bsonType: "string", pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" },
                age: { bsonType: "int", minimum: 0, maximum: 150 },
                status: { bsonType: "string", enum: ["active", "inactive", "banned"] },
                tags: { bsonType: "array", items: { bsonType: "string" }, uniqueItems: true }
            }
        }
    },
    validationLevel: "strict",    // strict (varsayilan) | moderate (mevcut uyumsuzlara dokunma)
    validationAction: "error"     // error (varsayilan) | warn (log'a yaz, izin ver)
});

Mevcut Koleksiyona Validation Ekleme

javascript
db.runCommand({
    collMod: "users",
    validator: {
        $jsonSchema: {
            bsonType: "object",
            required: ["name", "email"],
            properties: {
                name: { bsonType: "string" },
                email: { bsonType: "string" }
            }
        }
    },
    validationLevel: "moderate",
    validationAction: "error"
});

Schema Design Patterns

Embedding (Gömme) -- 1:few ilişkiler için

javascript
// Adres kullanici icine gomulu / Address embedded in user
{
    _id: ObjectId("..."),
    name: "Ali Yilmaz",
    email: "ali@test.com",
    addresses: [
        { type: "home", city: "Istanbul", street: "Istiklal Cad. 42" },
        { type: "work", city: "Istanbul", street: "Levent Plaza 5" }
    ]
}

Referencing (Referanslama) -- 1:many veya many:many için

javascript
// Siparis ayri koleksiyonda, user'a referans verir
// Order in separate collection, references user
{
    _id: ObjectId("..."),
    userId: ObjectId("user_id_here"),
    items: [
        { productId: ObjectId("prod_1"), quantity: 2, price: 29.99 },
        { productId: ObjectId("prod_2"), quantity: 1, price: 49.99 }
    ],
    total: 109.97,
    createdAt: ISODate("2025-01-15")
}

Kural / Rule: Birlikte okunan veri gömülür, bağımsız büyüyen veri referanslanır. (Data read together should be embedded; independently growing data should be referenced.)

Change Streams

Change Streams, MongoDB 3.6+ ile gelen real-time veri değişikliklerini dinleme mekanizmasıdır. Replica set gerektirir.

Node.js ile Change Stream

javascript
const changeStream = Order.watch([
    { $match: { operationType: { $in: ['insert', 'update'] } } }
], { fullDocument: 'updateLookup' });

changeStream.on('change', (change) => {
    console.log('Degisiklik:', change.operationType, change.fullDocument);
    if (change.operationType === 'insert') sendNotification(change.fullDocument);
});

Python ile Change Stream

python
resume_token = None
try:
    with db.orders.watch(full_document='updateLookup') as stream:
        for change in stream:
            print(f"Islem: {change['operationType']}")
            resume_token = stream.resume_token  # Kesintiden devam icin kaydet
except Exception:
    if resume_token:
        with db.orders.watch(resume_after=resume_token) as stream:
            for change in stream:
                print(f"Devam: {change['operationType']}")

Kullanım Senaryoları (Use Cases)

  • Bildirim sistemi: Yeni sipariş geldiğinde kullanıcıya bildirim gönder
  • Cache invalidation: Veri değiştiğinde Redis cache'i otomatik temizle
  • Veri senkronizasyonu: Değişiklikleri Elasticsearch veya başka sisteme aktar
  • Audit log: Tüm değişiklikleri ayrı bir koleksiyona kaydet

Mongoose (Node.js) ile Kullanım (Mongoose Usage)

javascript
const mongoose = require('mongoose');

// Baglanti / Connection
mongoose.connect('mongodb://admin:secret123@localhost:27017/myapp?authSource=admin');

// Schema ve Model tanimlama / Define Schema & Model
const userSchema = new mongoose.Schema({
    name:      { type: String, required: true, trim: true },
    email:     { type: String, required: true, unique: true, lowercase: true },
    age:       { type: Number, min: 0, max: 150 },
    tags:      [String],
    address:   {
        city:    String,
        country: { type: String, default: 'TR' }
    },
    isActive:  { type: Boolean, default: true },
    createdAt: { type: Date, default: Date.now }
});

userSchema.index({ email: 1 });
userSchema.index({ 'address.city': 1, age: -1 });

const User = mongoose.model('User', userSchema);

// CRUD
// Create
const user = await User.create({
    name: 'Ali Yilmaz', email: 'ali@test.com', age: 28, tags: ['admin']
});

// Read
const users = await User.find({ age: { $gt: 25 } }).sort({ name: 1 }).limit(10);
const single = await User.findOne({ email: 'ali@test.com' });
const byId = await User.findById('64a1b2c3d4e5f6...');

// Update
await User.findByIdAndUpdate(user._id, { $set: { age: 29 } }, { new: true });
await User.updateMany({ isActive: false }, { $set: { tags: [] } });

// Delete
await User.findByIdAndDelete(user._id);
await User.deleteMany({ isActive: false });

Virtuals -- Hesaplanan Alanlar (Computed Fields)

javascript
userSchema.virtual('fullName').get(function () {
    return `${this.firstName} ${this.lastName}`;
});

// Virtual'larin JSON ciktisinda gorunmesi icin
userSchema.set('toJSON', { virtuals: true });

Middleware / Hooks

javascript
// pre('save') -- kaydetmeden once
userSchema.pre('save', async function (next) {
    if (this.isModified('password')) {
        this.password = await bcrypt.hash(this.password, 12);
    }
    next();
});

// post('save') -- kaydettikten sonra
userSchema.post('save', function (doc) {
    console.log(`Kaydedildi: ${doc.email}`);
});

// pre('findOneAndUpdate') -- update oncesi
userSchema.pre('findOneAndUpdate', function (next) {
    this.set({ updatedAt: new Date() });
    next();
});

// pre('deleteOne') -- silmeden once iliskili verileri temizle
userSchema.pre('deleteOne', { document: true, query: false }, async function () {
    await Order.deleteMany({ userId: this._id });
});

Populate -- İlişkisel Veri Çekme (Relational Data Fetching)

javascript
// Basit populate
const order = await Order.findById(orderId).populate('userId', 'name email');

// Nested (deep) populate
const order = await Order.findById(orderId)
    .populate({
        path: 'userId',
        select: 'name email',
        populate: { path: 'companyId', select: 'name' }
    })
    .populate('items.productId', 'name price');

// Kosullu populate
const orders = await Order.find()
    .populate({ path: 'userId', match: { isActive: true }, select: 'name email' });

Discriminators -- Schema Inheritance

javascript
const eventSchema = new mongoose.Schema(
    { message: String, timestamp: Date },
    { discriminatorKey: 'type' }
);
const Event = mongoose.model('Event', eventSchema);

const ClickEvent = Event.discriminator('ClickEvent',
    new mongoose.Schema({ element: String, url: String })
);
const PurchaseEvent = Event.discriminator('PurchaseEvent',
    new mongoose.Schema({ productId: mongoose.Schema.Types.ObjectId, amount: Number })
);

// Tum event'leri sorgula
const allEvents = await Event.find();           // Her iki tip de gelir
const purchases = await PurchaseEvent.find();   // Sadece satin alma

Plugins

javascript
// Timestamps (yerlesik)
const postSchema = new mongoose.Schema(
    { title: String, content: String },
    { timestamps: true }  // createdAt + updatedAt otomatik
);

// Pagination (mongoose-paginate-v2)
const mongoosePaginate = require('mongoose-paginate-v2');
postSchema.plugin(mongoosePaginate);
const result = await Post.paginate({ status: 'published' }, { page: 2, limit: 10 });

// Kendi plugin'ini yaz
function softDeletePlugin(schema) {
    schema.add({ deletedAt: { type: Date, default: null } });
    schema.methods.softDelete = function () {
        this.deletedAt = new Date();
        return this.save();
    };
    schema.pre(/^find/, function () {
        if (!this.getQuery().deletedAt) this.where({ deletedAt: null });
    });
}
userSchema.plugin(softDeletePlugin);

PyMongo (Python) ile Kullanım (PyMongo Usage)

python
from pymongo import MongoClient
from datetime import datetime

# Baglanti / Connection
client = MongoClient('mongodb://admin:secret123@localhost:27017/')
db = client['myapp']
users = db['users']

# Create
user_id = users.insert_one({
    'name': 'Ali Yilmaz',
    'email': 'ali@test.com',
    'age': 28,
    'tags': ['admin'],
    'created_at': datetime.now()
}).inserted_id

# Read
all_users = list(users.find({'age': {'$gt': 25}}).sort('name', 1).limit(10))
one_user = users.find_one({'email': 'ali@test.com'})

# Update
users.update_one({'email': 'ali@test.com'}, {'$set': {'age': 29}})
users.update_many({'age': {'$lt': 20}}, {'$set': {'status': 'young'}})

# Delete
users.delete_one({'email': 'ali@test.com'})

# Aggregation
pipeline = [
    {'$match': {'age': {'$gt': 20}}},
    {'$group': {'_id': '$address.city', 'count': {'$sum': 1}}},
    {'$sort': {'count': -1}}
]
results = list(users.aggregate(pipeline))

Güvenlik (Security)

Kimlik Doğrulama -- SCRAM Authentication

javascript
// Admin kullanici olustur
use admin
db.createUser({
    user: "appAdmin",
    pwd: "guvenliSifre123!",
    roles: [
        { role: "userAdminAnyDatabase", db: "admin" },
        { role: "readWriteAnyDatabase", db: "admin" }
    ]
});

// Uygulama kullanicisi (sinirli yetki)
use myapp
db.createUser({
    user: "appUser",
    pwd: "appSifre456!",
    roles: [{ role: "readWrite", db: "myapp" }]
});

Built-in Roller (Built-in Roles)

RolAçıklama
readKoleksiyonları okuma yetkisi
readWriteOkuma + yazma yetkisi
dbAdminIndex, istatistik, validation yönetimi
userAdminKullanıcı ve rol oluşturma/yönetme
clusterAdminReplica set ve sharding yönetimi
rootTüm yetkiler (dikkatli kullan)

Custom Role Oluşturma (Custom Role Creation)

javascript
db.createRole({
    role: "analyticsReader",
    privileges: [
        { resource: { db: "myapp", collection: "orders" }, actions: ["find", "aggregate"] },
        { resource: { db: "myapp", collection: "products" }, actions: ["find"] }
    ],
    roles: []
});

TLS/SSL Bağlantı (TLS/SSL Connection)

bash
# mongod.conf
net:
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/ssl/mongodb.pem
    CAFile: /etc/ssl/ca.pem

# Baglanma
mongosh "mongodb://localhost:27017/myapp" --tls --tlsCAFile /etc/ssl/ca.pem

Field-Level Encryption (Client-Side)

javascript
const client = new MongoClient('mongodb://localhost:27017', {
    autoEncryption: {
        keyVaultNamespace: 'encryption.__keyVault',
        kmsProviders: { local: { key: masterKey } },  // Uretimde AWS/Azure/GCP KMS kullan
        schemaMap: {
            'myapp.users': {
                bsonType: 'object',
                properties: {
                    ssn: { encrypt: { bsonType: 'string', algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' } }
                }
            }
        }
    }
});

Injection Korunma (Injection Prevention)

javascript
// YANLIS -- kullanici girdisi dogrudan sorguya
const user = await db.users.findOne({ name: req.query.name });
// { $gt: "" } girilirse tum kullanicilar doner!

// DOGRU -- sanitize et
const sanitize = require('mongo-sanitize');
const user = await db.users.findOne({ name: sanitize(req.query.name) });

// DOGRU -- tip kontrolu
if (typeof req.query.name !== 'string') return res.status(400).json({ error: 'Gecersiz' });

// $where ve $function kullanmaktan kacin (kod injection riski)

Atlas Güvenlik (Atlas Security)

  • IP Whitelist: Sadece belirli IP adreslerinden erişime izin ver
  • VPC Peering: Atlas cluster'ı özel ağ üzerinden bağla
  • Audit Log: Tüm veritabanı işlemlerini denetim için kaydet
  • Encryption at Rest: Veriler diskte şifrelenir (AES-256)

MongoDB Atlas

Atlas, MongoDB'nin yönetilen bulut veritabanı hizmetidir (managed service).

Cluster Oluşturma

  1. cloud.mongodb.com adresinden hesap oluştur
  2. M0 Free Tier: Ücretsiz, 512 MB, öğrenme ve prototip için ideal
  3. Cloud provider seç (AWS, GCP, Azure) ve region belirle
  4. Kullanıcı + şifre oluştur, IP whitelist'e ekle

Connection String

bash
mongodb+srv://kullanici:sifre@cluster0.xxxxx.mongodb.net/myapp?retryWrites=true&w=majority

Lucene tabanlı full-text arama motoru. Text index'ten çok daha güçlü.

javascript
db.products.aggregate([
    { $search: {
        index: "default",
        text: {
            query: "kablosuz kulaklik",
            path: ["name", "description"],
            fuzzy: { maxEdits: 1 }
        }
    }},
    { $project: { name: 1, price: 1, score: { $meta: "searchScore" } } },
    { $limit: 10 }
]);

// Autocomplete
db.products.aggregate([
    { $search: { index: "autocomplete_index", autocomplete: { query: "kulo", path: "name" } } },
    { $limit: 5 }, { $project: { name: 1 } }
]);

Atlas Charts

  • Doğrudan Atlas cluster'a bağlanır (ETL gerekmez)
  • Bar, line, pie, heatmap, geo grafik tipleri
  • Dashboard paylaşma ve iframe ile gömme desteği

Sık Kullanılan Komutlar (Quick Reference)

CommandDescription
show dbsVeritabanlarını listele
show collectionsKoleksiyonları listele
db.collection.find().pretty()Okunaklı çıktı
db.collection.countDocuments({})Doküman say
db.collection.getIndexes()İndeksleri listele
db.collection.explain().find({})Sorgu planını göster
db.serverStatus()Sunucu durumunu göster
mongodump --db myapp --out backup/Yedek al
mongorestore --db myapp backup/myapp/Geri yükle

İpuçları ve Best Practices

Embedding vs Referencing Karar Ağacı (Decision Tree)

KriterEmbeddingReferencing
İlişki tipi1:1, 1:few1:many, many:many
ErişimHer zaman birlikte okunuyorBağımsız erişim gerekiyor
BoyutKüçük, sınırlı büyümeSınırlardan bağımsız büyüme
GüncellemeNadir güncellenirSık güncellenir
Doküman limiti16 MB altında16 MB'ı aşabilir

ObjectId'den Tarih Çıkarma (Extracting Date from ObjectId)

javascript
const id = ObjectId("65a1b2c3d4e5f6a7b8c9d0e1");
id.getTimestamp();  // ISODate("2024-01-12T...")
// createdAt alani olmadan olusturma tarihine eris

Schema Design Patterns

  • Bucket Pattern: Zaman serisi verileri tek dokümanda grupla (IoT, log)
  • Computed Pattern: Sık hesaplanan değerleri önceden sakla (toplam, ortalama)
  • Subset Pattern: Büyük dokümanlardan sık erişilen alt kümeyi ana dokümanda tut
  • Outlier Pattern: Büyük array'ler için ek dokümanlara taşma (hasOverflow: true)

Performans İpuçları

javascript
// 1. Projection -- sadece gerekli alanlari cek
const users = await User.find({ isActive: true }, { name: 1, email: 1 });

// 2. lean() -- plain JS object doner, Mongoose overhead yok (sadece okuma icin)
const users = await User.find({ isActive: true }).lean();

// 3. Compound index ESR kuralini uygula (Equality -> Sort -> Range)

// 4. estimatedDocumentCount -- buyuk koleksiyonlarda O(1)
const count = await User.estimatedDocumentCount();

// 5. bulkWrite -- tek seferde coklu islem (round-trip azalt)
await User.bulkWrite([
    { insertOne: { document: { name: "Yeni", email: "yeni@test.com" } } },
    { updateOne: { filter: { email: "ali@test.com" }, update: { $set: { age: 30 } } } },
    { deleteOne: { filter: { email: "eski@test.com" } } }
]);

// 6. Cursor -- buyuk veri setlerini bellek tasirmadan isle
const cursor = User.find({ isActive: true }).cursor();
for await (const user of cursor) {
    await processUser(user);
}

Ilgili Rehberler

Veritabani

Diger Kategoriler

Developer Guides & Technical References