MongoDB Temelleri
MongoDB’nin mimari yapısı ve NoSQL kavramı
NoSQL Kavramı
NoSQL, “Not Only SQL” (Yalnızca SQL Değil) anlamına gelir ve geleneksel ilişkisel veritabanı yönetim sistemlerinden (RDBMS) farklı bir yaklaşım sunar. NoSQL veritabanları, büyük ölçekli, dağıtık ve yapılandırılmamış veya yarı yapılandırılmış verileri depolamak ve yönetmek için tasarlanmıştır. NoSQL veritabanları, özellikle web uygulamaları, büyük veri analitiği ve gerçek zamanlı uygulamalar gibi senaryolarda popülerdir.
NoSQL veritabanlarının temel özellikleri şunlardır:
- Esnek Şema: Geleneksel SQL veritabanlarının aksine, NoSQL veritabanları sabit bir şema gerektirmez. Bu, veri yapısının zamanla değişebileceği anlamına gelir.
- Yatay Ölçeklenebilirlik: NoSQL veritabanları, verileri birden fazla sunucuya dağıtarak yatay olarak ölçeklenebilir.
- Yüksek Performans: NoSQL veritabanları, büyük miktarda veriyi hızlı bir şekilde işlemek için optimize edilmiştir.
- Dağıtık Mimari: NoSQL veritabanları, verileri birden fazla düğümde depolayarak yüksek kullanılabilirlik ve hata toleransı sağlar.
MongoDB’nin Mimarisi
MongoDB, belge tabanlı bir NoSQL veritabanıdır. Veriler, JSON benzeri BSON (Binary JSON) formatında saklanır. MongoDB’nin mimarisi, geleneksel ilişkisel veritabanlarından farklıdır ve aşağıdaki temel bileşenlerden oluşur:
- Belge (Document): MongoDB’de veriler, belgeler halinde saklanır. Her belge, bir JSON nesnesine benzer ve anahtar-değer çiftlerinden oluşur. Örneğin:
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "Ahmet",
"age": 30,
"address": {
"city": "Ankara",
"country": "Turkey"
}
}
Bu örnekte, _id
alanı MongoDB tarafından otomatik olarak oluşturulan benzersiz bir tanımlayıcıdır.
- Koleksiyon (Collection): Belgeler, koleksiyonlar halinde gruplanır. Koleksiyonlar, ilişkisel veritabanlarındaki tablolara benzer, ancak sabit bir şema gerektirmez. Örneğin, bir
users
koleksiyonu, farklı yapıda belgeler içerebilir. - Veritabanı (Database): Koleksiyonlar, veritabanları içinde gruplanır. Bir MongoDB sunucusu, birden fazla veritabanı barındırabilir.
- Sharding: MongoDB, büyük veri kümelerini yönetmek için sharding adı verilen bir yöntem kullanır. Sharding, verileri birden fazla sunucuya dağıtarak yatay ölçeklenebilirlik sağlar.
- Replikasyon: MongoDB, yüksek kullanılabilirlik sağlamak için replikasyon kullanır. Veriler, birden fazla sunucuya (replica set) kopyalanır, böylece bir sunucu arızalandığında diğer sunucular hizmet vermeye devam eder.
MongoDB’de Temel İşlemler
MongoDB’de temel CRUD (Create, Read, Update, Delete) işlemleri, MongoDB Shell veya MongoDB’nin resmi sürücüleri (örneğin, Python, Node.js, Java) kullanılarak gerçekleştirilebilir. Aşağıda, MongoDB Shell kullanılarak yapılan temel işlemlerin örnekleri bulunmaktadır.
Veri Ekleme (Create)
// 'users' koleksiyonuna yeni bir belge ekleme
db.users.insertOne({
name: "Mehmet",
age: 25,
address: {
city: "İstanbul",
country: "Turkey"
}
});
Veri Okuma (Read)
// 'users' koleksiyonundaki tüm belgeleri okuma
db.users.find();
// Belirli bir koşula göre belge okuma
db.users.find({ name: "Mehmet" });
Veri Güncelleme (Update)
// 'users' koleksiyonundaki bir belgeyi güncelleme
db.users.updateOne(
{ name: "Mehmet" },
{ $set: { age: 26 } }
);
Veri Silme (Delete)
// 'users' koleksiyonundaki bir belgeyi silme
db.users.deleteOne({ name: "Mehmet" });
MongoDB’nin Avantajları
- Esnek Şema: MongoDB, sabit bir şema gerektirmez, bu da uygulamanın geliştirme sürecinde esneklik sağlar.
- Yüksek Performans: MongoDB, büyük veri kümeleri üzerinde hızlı okuma ve yazma işlemleri gerçekleştirir.
- Yatay Ölçeklenebilirlik: Sharding ile veriler birden fazla sunucuya dağıtılabilir, bu da sistemin büyümesine olanak tanır.
- Yüksek Kullanılabilirlik: Replikasyon sayesinde, bir sunucu arızalandığında bile sistem çalışmaya devam eder.
Döküman tabanlı veritabanı mantığı
Döküman Tabanlı Veritabanı Nedir?
Döküman tabanlı veritabanları, verileri dökümanlar halinde saklar. Bu dökümanlar, genellikle JSON (JavaScript Object Notation) veya BSON (Binary JSON) formatında olur. Her döküman, birbirinden bağımsız ve kendi içinde yapılandırılmış veri birimidir. Döküman tabanlı veritabanları, özellikle esnek şema yapısı ve hızlı veri erişimi sağlamasıyla öne çıkar.
Döküman Tabanlı Veritabanlarının Temel Özellikleri:
- Esnek Şema: Her döküman, farklı bir yapıya sahip olabilir. Bu, uygulamanın ihtiyaçlarına göre veri yapısının dinamik olarak değiştirilebilmesini sağlar.
- Hiyerarşik Veri Yapısı: Dökümanlar, iç içe geçmiş (nested) veri yapılarına izin verir. Bu, karmaşık veri modellerini temsil etmeyi kolaylaştırır.
- Hızlı Veri Erişimi: Dökümanlar, tek bir birim olarak saklanır ve okunur. Bu, ilişkisel veritabanlarındaki JOIN işlemlerine kıyasla daha hızlı veri erişimi sağlar.
- JSON/BSON Formatı: Dökümanlar, insan tarafından okunabilen JSON formatında veya binary JSON (BSON) formatında saklanır. BSON, JSON’dan daha verimlidir ve ek veri türlerini destekler.
MongoDB’de Döküman Yapısı
MongoDB’de dökümanlar, JSON benzeri bir format olan BSON (Binary JSON) olarak saklanır. Her döküman, anahtar-değer çiftlerinden oluşur ve iç içe geçmiş yapılar (nested structures) içerebilir.
Örnek Bir Döküman:
{
"_id": ObjectId("64a1b2c3d4e5f6a7b8c9d0e1"),
"name": "Ayşe",
"age": 28,
"address": {
"city": "İzmir",
"country": "Turkey"
},
"hobbies": ["yoga", "müzik", "seyahat"],
"isActive": true
}
_id
: MongoDB tarafından otomatik olarak oluşturulan benzersiz bir tanımlayıcıdır. Her dökümanın birincil anahtarıdır.name
,age
: Basit anahtar-değer çiftleri.address
: İç içe geçmiş bir döküman (nested document).hobbies
: Bir dizi (array).isActive
: Boolean türünde bir değer.
Döküman Tabanlı Veritabanlarının Avantajları
- Esnek Şema Yapısı:
- Geleneksel ilişkisel veritabanlarında, veriler sabit bir şemaya uymak zorundadır. Örneğin, bir tablodaki tüm satırlar aynı sütunlara sahip olmalıdır.
- Döküman tabanlı veritabanlarında ise her döküman farklı bir yapıya sahip olabilir. Bu, uygulamanın geliştirme sürecinde büyük bir esneklik sağlar. Örnek:
// İlk döküman
{
"name": "Ali",
"age": 30
}
// İkinci döküman
{
"name": "Zeynep",
"email": "zeynep@example.com",
"address": {
"city": "Ankara"
}
}
Bu iki döküman, aynı koleksiyonda bulunabilir ve farklı alanlara sahip olabilir.
- Hiyerarşik Veri Yapısı:
- Dökümanlar, iç içe geçmiş yapılar (nested documents) ve diziler (arrays) içerebilir. Bu, karmaşık veri modellerini temsil etmeyi kolaylaştırır. Örnek:
{
"name": "Mehmet",
"orders": [
{
"orderId": 101,
"product": "Laptop",
"quantity": 1
},
{
"orderId": 102,
"product": "Mouse",
"quantity": 2
}
]
}
- Hızlı Veri Erişimi:
- Dökümanlar, tek bir birim olarak saklanır ve okunur. Bu, ilişkisel veritabanlarındaki JOIN işlemlerine kıyasla daha hızlıdır.
- Özellikle büyük veri kümelerinde, döküman tabanlı veritabanları daha iyi performans sunar.
- JSON/BSON Formatı:
- JSON, modern programlama dilleriyle uyumlu ve kolayca işlenebilir bir formattır.
- BSON, JSON’un binary versiyonudur ve ek veri türlerini (örneğin, tarih, binary veri) destekler.
MongoDB’de Döküman İşlemleri
MongoDB’de dökümanlar üzerinde temel CRUD (Create, Read, Update, Delete) işlemleri gerçekleştirilebilir. Aşağıda, MongoDB Shell kullanılarak yapılan temel işlemlerin örnekleri bulunmaktadır.
1. Döküman Ekleme (Create)
// 'users' koleksiyonuna yeni bir döküman ekleme
db.users.insertOne({
name: "Ahmet",
age: 35,
address: {
city: "Bursa",
country: "Turkey"
},
hobbies: ["futbol", "kitap okuma"]
});
2. Döküman Okuma (Read)
// Tüm dökümanları okuma
db.users.find();
// Belirli bir koşula göre döküman okuma
db.users.find({ name: "Ahmet" });
// İç içe geçmiş alanlara göre sorgulama
db.users.find({ "address.city": "Bursa" });
3. Döküman Güncelleme (Update)
// 'users' koleksiyonundaki bir dökümanı güncelleme
db.users.updateOne(
{ name: "Ahmet" },
{ $set: { age: 36 } }
);
// Diziye yeni bir öğe ekleme
db.users.updateOne(
{ name: "Ahmet" },
{ $push: { hobbies: "yüzme" } }
);
4. Döküman Silme (Delete)
// 'users' koleksiyonundaki bir dökümanı silme
db.users.deleteOne({ name: "Ahmet" });
Döküman Tabanlı Veritabanlarının Kullanım Alanları
- İçerik Yönetim Sistemleri (CMS): Esnek şema yapısı, farklı türde içeriklerin saklanmasını kolaylaştırır.
- Kullanıcı Profilleri: Her kullanıcının farklı özelliklere sahip olabileceği senaryolarda idealdir.
- Büyük Veri ve Gerçek Zamanlı Uygulamalar: Hızlı veri erişimi ve yatay ölçeklenebilirlik, büyük veri uygulamaları için uygundur.
- IoT (Nesnelerin İnterneti): Farklı cihazlardan gelen yapılandırılmamış verilerin saklanması için kullanılır.
BSON formatı ve JSON ile ilişkisi
JSON (JavaScript Object Notation) Nedir?
JSON, verileri insan tarafından okunabilir bir metin formatında temsil eden hafif bir veri değişim formatıdır. JSON, anahtar-değer çiftleri ve dizilerden oluşur ve modern programlama dilleriyle uyumludur. JSON, özellikle web uygulamalarında veri alışverişi için yaygın olarak kullanılır.
JSON Örneği:
{
"name": "Ahmet",
"age": 30,
"address": {
"city": "Ankara",
"country": "Turkey"
},
"hobbies": ["yoga", "müzik", "seyahat"]
}
- Anahtar-değer çiftleri:
"name": "Ahmet"
,"age": 30
gibi. - İç içe geçmiş nesneler:
"address"
alanı gibi. - Diziler:
"hobbies"
alanı gibi.
BSON (Binary JSON) Nedir?
BSON, JSON’un binary (ikili) bir temsilidir. MongoDB, verileri depolamak ve ağ üzerinden iletmek için BSON formatını kullanır. BSON, JSON’dan daha verimlidir ve ek veri türlerini destekler. BSON’un temel özellikleri şunlardır:
- Binary Format: BSON, JSON’dan farklı olarak binary (ikili) bir formattır. Bu, verilerin daha kompakt ve hızlı işlenebilir olmasını sağlar.
- Ek Veri Türleri: BSON, JSON’un desteklemediği ek veri türlerini destekler. Örneğin, tarih (Date), binary veri (BinData), ObjectId gibi.
- Hızlı Veri Erişimi: BSON, verilere hızlı erişim sağlamak için optimize edilmiştir. Bu, özellikle büyük veri kümelerinde performans avantajı sağlar.
BSON’un Desteklediği Ek Veri Türleri:
- ObjectId: MongoDB’de her dökümanın benzersiz kimliği (ID).
- Date: Tarih ve saat bilgisi.
- BinData: Binary veri (örneğin, resim, video).
- NumberLong: 64-bit tam sayı.
- NumberDecimal: Yüksek hassasiyetli ondalık sayı.
JSON ve BSON Arasındaki Farklar
Özellik | JSON | BSON |
---|---|---|
Format | Metin tabanlı (text-based) | Binary (ikili) |
Veri Türleri | Sınırlı (string, number, boolean, array, object, null) | Genişletilmiş (Date, ObjectId, BinData, vb.) |
Okunabilirlik | İnsan tarafından okunabilir | İnsan tarafından okunamaz |
Veri Boyutu | Daha büyük | Daha küçük (binary sıkıştırma) |
Performans | Daha yavaş | Daha hızlı |
MongoDB’de BSON Kullanımı
MongoDB, verileri BSON formatında saklar ve işler. Bu, verilerin daha hızlı okunmasını ve yazılmasını sağlar. Ayrıca, BSON’un ek veri türleri, MongoDB’nin esnek ve güçlü bir veritabanı olmasına katkıda bulunur.
Örnek BSON Dökümanı:
Aşağıda, MongoDB’de bir dökümanın BSON formatında nasıl saklandığını gösteren bir örnek bulunmaktadır:
{
"_id": ObjectId("64a1b2c3d4e5f6a7b8c9d0e1"),
"name": "Ahmet",
"age": 30,
"birthdate": ISODate("1993-05-15T00:00:00Z"),
"profileImage": BinData(0, "base64EncodedData"),
"balance": NumberDecimal("1000.50")
}
_id
: MongoDB tarafından otomatik olarak oluşturulan benzersiz bir tanımlayıcı (ObjectId).birthdate
: Tarih veri türü (Date).profileImage
: Binary veri (BinData).balance
: Yüksek hassasiyetli ondalık sayı (NumberDecimal).
MongoDB’de JSON ve BSON Dönüşümü
MongoDB, JSON ve BSON arasında otomatik olarak dönüşüm yapar. Örneğin, bir dökümanı MongoDB’ye eklerken JSON formatında gönderirsiniz, ancak MongoDB bu veriyi BSON formatında saklar. Benzer şekilde, verileri okurken BSON formatındaki veriler JSON formatına dönüştürülür.
Örnek: JSON’dan BSON’a Dönüşüm
// JSON formatında bir döküman
const user = {
name: "Ahmet",
age: 30,
birthdate: new Date("1993-05-15"),
profileImage: Buffer.from("base64EncodedData", "base64"),
balance: NumberDecimal("1000.50")
};
// MongoDB'ye ekleme (JSON otomatik olarak BSON'a dönüştürülür)
db.users.insertOne(user);
Örnek: BSON’dan JSON’a Dönüşüm
// MongoDB'den döküman okuma (BSON otomatik olarak JSON'a dönüştürülür)
const user = db.users.findOne({ name: "Ahmet" });
console.log(user);
BSON’un Avantajları
- Verimlilik: BSON, JSON’dan daha küçük bir boyuta sahiptir ve ağ üzerinden daha hızlı iletilir.
- Genişletilebilirlik: BSON, JSON’un desteklemediği ek veri türlerini destekler.
- Performans: BSON, verilere hızlı erişim sağlar ve büyük veri kümelerinde daha iyi performans sunar.
- MongoDB ile Uyum: BSON, MongoDB’nin temel veri formatıdır ve MongoDB’nin tüm özellikleriyle uyumludur.
Collections ve Documents kavramları
Documents (Dökümanlar) Nedir?
MongoDB’de veriler, dökümanlar halinde saklanır. Her döküman, JSON benzeri bir format olan BSON (Binary JSON) olarak temsil edilir. Dökümanlar, anahtar-değer çiftlerinden oluşur ve iç içe geçmiş yapılar (nested structures) içerebilir.
Döküman Özellikleri:
- Esnek Yapı: Her döküman, farklı bir yapıya sahip olabilir. Bu, MongoDB’nin esnek şema yapısını destekler.
- Anahtar-Değer Çiftleri: Dökümanlar, anahtar-değer çiftlerinden oluşur. Anahtarlar string, değerler ise çeşitli veri türlerinde olabilir (string, number, boolean, array, object, vb.).
- İç İçe Geçmiş Yapılar: Dökümanlar, iç içe geçmiş nesneler ve diziler içerebilir. Bu, karmaşık veri modellerini temsil etmeyi kolaylaştırır.
Örnek Bir Döküman:
{
"_id": ObjectId("64a1b2c3d4e5f6a7b8c9d0e1"),
"name": "Ahmet",
"age": 30,
"address": {
"city": "Ankara",
"country": "Turkey"
},
"hobbies": ["yoga", "müzik", "seyahat"]
}
_id
: MongoDB tarafından otomatik olarak oluşturulan benzersiz bir tanımlayıcıdır. Her dökümanın birincil anahtarıdır.name
,age
: Basit anahtar-değer çiftleri.address
: İç içe geçmiş bir nesne (nested document).hobbies
: Bir dizi (array).
Collections (Koleksiyonlar) Nedir?
MongoDB’de dökümanlar, koleksiyonlar halinde gruplanır. Koleksiyonlar, ilişkisel veritabanlarındaki tablolara benzer, ancak sabit bir şema gerektirmez. Bir koleksiyon, farklı yapıda dökümanlar içerebilir.
Koleksiyon Özellikleri:
- Esnek Şema: Koleksiyonlar, sabit bir şema gerektirmez. Her döküman, farklı bir yapıya sahip olabilir.
- Döküman Gruplama: Koleksiyonlar, mantıksal olarak ilişkili dökümanları gruplamak için kullanılır. Örneğin, bir
users
koleksiyonu, tüm kullanıcı dökümanlarını içerebilir. - Performans: Koleksiyonlar, verilere hızlı erişim sağlamak için optimize edilmiştir.
Örnek Bir Koleksiyon:
// 'users' koleksiyonu
[
{
"_id": ObjectId("64a1b2c3d4e5f6a7b8c9d0e1"),
"name": "Ahmet",
"age": 30,
"address": {
"city": "Ankara",
"country": "Turkey"
}
},
{
"_id": ObjectId("64a1b2c3d4e5f6a7b8c9d0e2"),
"name": "Zeynep",
"email": "zeynep@example.com",
"hobbies": ["kitap okuma", "yürüyüş"]
}
]
Bu örnekte, users
koleksiyonu iki farklı yapıda döküman içerir. İlk döküman name
, age
ve address
alanlarına sahipken, ikinci döküman name
, email
ve hobbies
alanlarına sahiptir.
Collections ve Documents Arasındaki İlişki
- Koleksiyonlar, dökümanların mantıksal olarak gruplandığı birimlerdir.
- Dökümanlar, koleksiyonlar içinde saklanan veri birimleridir.
- Bir koleksiyon, sıfır veya daha fazla döküman içerebilir.
- Koleksiyonlar, veritabanı içinde gruplanır. Bir MongoDB veritabanı, birden fazla koleksiyon içerebilir.
Örnek Veritabanı Yapısı:
- Veritabanı:
myDatabase
- Koleksiyon:
users
- Döküman:
{ "name": "Ahmet", "age": 30 }
- Döküman:
{ "name": "Zeynep", "email": "zeynep@example.com" }
- Döküman:
- Koleksiyon:
products
- Döküman:
{ "productName": "Laptop", "price": 5000 }
- Döküman:
{ "productName": "Mouse", "price": 200 }
- Döküman:
MongoDB’de Collections ve Documents ile Çalışma
MongoDB’de koleksiyonlar ve dökümanlar üzerinde temel CRUD (Create, Read, Update, Delete) işlemleri gerçekleştirilebilir. Aşağıda, MongoDB Shell kullanılarak yapılan temel işlemlerin örnekleri bulunmaktadır.
1. Koleksiyon Oluşturma ve Döküman Ekleme
// 'users' koleksiyonuna yeni bir döküman ekleme
db.users.insertOne({
name: "Mehmet",
age: 25,
address: {
city: "İstanbul",
country: "Turkey"
}
});
2. Döküman Okuma
// 'users' koleksiyonundaki tüm dökümanları okuma
db.users.find();
// Belirli bir koşula göre döküman okuma
db.users.find({ name: "Mehmet" });
// İç içe geçmiş alanlara göre sorgulama
db.users.find({ "address.city": "İstanbul" });
3. Döküman Güncelleme
// 'users' koleksiyonundaki bir dökümanı güncelleme
db.users.updateOne(
{ name: "Mehmet" },
{ $set: { age: 26 } }
);
// Diziye yeni bir öğe ekleme
db.users.updateOne(
{ name: "Mehmet" },
{ $push: { hobbies: "yüzme" } }
);
4. Döküman Silme
// 'users' koleksiyonundaki bir dökümanı silme
db.users.deleteOne({ name: "Mehmet" });
5. Koleksiyon Silme
// 'users' koleksiyonunu silme
db.users.drop();
Collections ve Documents’ın Avantajları
- Esnek Şema: Koleksiyonlar, sabit bir şema gerektirmez. Bu, uygulamanın geliştirme sürecinde esneklik sağlar.
- Hızlı Veri Erişimi: Dökümanlar, tek bir birim olarak saklanır ve okunur. Bu, ilişkisel veritabanlarındaki JOIN işlemlerine kıyasla daha hızlıdır.
- Karmaşık Veri Modelleri: İç içe geçmiş yapılar ve diziler, karmaşık veri modellerini temsil etmeyi kolaylaştırır.
- Ölçeklenebilirlik: MongoDB, yatay ölçeklenebilirlik sağlar. Bu, büyük veri kümeleri ve yüksek trafikli uygulamalar için idealdir.
MongoDB Atlas kullanımı ve cloud çözümleri
MongoDB Atlas Nedir?
MongoDB Atlas, MongoDB’nin resmi bulut tabanlı veritabanı hizmetidir. AWS, Google Cloud ve Microsoft Azure gibi büyük bulut sağlayıcıları üzerinde çalışır. MongoDB Atlas, kullanıcıların veritabanlarını bulut ortamında kolayca dağıtmasını, yönetmesini ve ölçeklendirmesini sağlar. Ayrıca, otomatik yedekleme, güvenlik, izleme ve performans optimizasyonu gibi özellikler sunar.
MongoDB Atlas’ın Temel Özellikleri:
- Bulut Tabanlı: AWS, Google Cloud ve Azure gibi bulut sağlayıcıları üzerinde çalışır.
- Otomatik Yönetim: Veritabanı yönetimi, güncellemeler, yedeklemeler ve ölçeklendirme otomatik olarak yapılır.
- Yüksek Kullanılabilirlik: Replikasyon ve sharding ile yüksek kullanılabilirlik sağlanır.
- Güvenlik: Veri şifreleme, ağ izolasyonu ve kimlik doğrulama gibi güvenlik özellikleri sunar.
- Ölçeklenebilirlik: Veritabanı, uygulamanın ihtiyaçlarına göre otomatik olarak ölçeklenebilir.
- İzleme ve Analiz: Performans izleme, sorgu analizi ve hata ayıklama araçları sunar.
MongoDB Atlas’ın Avantajları
- Kolay Kurulum: MongoDB Atlas, birkaç tıklama ile veritabanı kurulumu sağlar. Kullanıcılar, sunucu yönetimi ve yazılım güncellemeleri gibi karmaşık işlemlerle uğraşmak zorunda kalmaz.
- Otomatik Ölçeklendirme: Uygulamanın ihtiyaçlarına göre otomatik olarak ölçeklenebilir. Bu, trafik artışlarında performans sorunlarını önler.
- Yüksek Kullanılabilirlik: Replikasyon ve sharding ile veritabanı yüksek kullanılabilirlik sağlar. Bir sunucu arızalandığında, diğer sunucular hizmet vermeye devam eder.
- Güvenlik: Veri şifreleme, ağ izolasyonu ve kimlik doğrulama gibi güvenlik özellikleri, verilerin güvende olmasını sağlar.
- Maliyet Etkin: Kullanıcılar, yalnızca kullandıkları kaynaklar için ödeme yapar. Bu, maliyetleri optimize eder.
MongoDB Atlas Kullanımı
MongoDB Atlas’ı kullanmak için aşağıdaki adımları izleyebilirsiniz:
1. MongoDB Atlas Hesabı Oluşturma
- MongoDB Atlas web sitesine gidin.
- Bir hesap oluşturun veya mevcut bir hesapla giriş yapın.
2. Cluster (Küme) Oluşturma
- MongoDB Atlas paneline gidin ve “Build a Cluster” (Küme Oluştur) butonuna tıklayın.
- Bulut sağlayıcısını (AWS, Google Cloud, Azure) ve bölgeyi seçin.
- Küme boyutunu ve özelliklerini belirleyin (örneğin, M0 ücretsiz tier veya daha büyük bir tier).
- Küme oluşturma işlemini başlatın.
3. Veritabanı Kullanıcısı ve Bağlantı Ayarları
- Küme oluşturulduktan sonra, veritabanına erişim için bir kullanıcı oluşturun.
- IP adresinizi beyaz listeye ekleyin (güvenlik için).
- Bağlantı dizesini (connection string) alın. Bu dize, uygulamanızın MongoDB Atlas’a bağlanmasını sağlar.
4. Veritabanına Bağlanma
MongoDB Atlas’a bağlanmak için aşağıdaki örnekleri kullanabilirsiniz:
Node.js ile Bağlantı Örneği:
const { MongoClient } = require("mongodb");
// MongoDB Atlas bağlantı dizesi
const uri = "mongodb+srv://<username>:<password>@cluster0.mongodb.net/myDatabase?retryWrites=true&w=majority";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
async function run() {
try {
await client.connect();
console.log("MongoDB Atlas'a bağlandı!");
const database = client.db("myDatabase");
const collection = database.collection("users");
// Örnek sorgu
const result = await collection.insertOne({ name: "Ahmet", age: 30 });
console.log("Döküman eklendi:", result.insertedId);
} finally {
await client.close();
}
}
run().catch(console.dir);
Python ile Bağlantı Örneği:
from pymongo import MongoClient
# MongoDB Atlas bağlantı dizesi
uri = "mongodb+srv://<username>:<password>@cluster0.mongodb.net/myDatabase?retryWrites=true&w=majority"
client = MongoClient(uri)
db = client.myDatabase
collection = db.users
# Örnek sorgu
result = collection.insert_one({"name": "Ahmet", "age": 30})
print("Döküman eklendi:", result.inserted_id)
MongoDB Atlas’ın Bulut Çözümleri
MongoDB Atlas, bulut tabanlı bir hizmet olarak aşağıdaki çözümleri sunar:
- Global Clusters (Küresel Kümeler): Verileri dünya çapında birden fazla bölgede dağıtarak düşük gecikme süresi ve yüksek kullanılabilirlik sağlar.
- Serverless (Sunucusuz): Kullanıcılar, sunucu yönetimiyle uğraşmadan otomatik ölçeklenebilir veritabanları oluşturabilir.
- Data Lake (Veri Gölü): Büyük veri analitiği için MongoDB verilerini doğrudan analiz edebilirsiniz.
- Full-Text Search (Tam Metin Arama): Veritabanı içinde hızlı ve güçlü tam metin arama özellikleri sunar.
- Real-Time Analytics (Gerçek Zamanlı Analiz): Veriler üzerinde gerçek zamanlı analizler yapabilirsiniz.
MongoDB Atlas’ın Kullanım Senaryoları
- Web Uygulamaları: MongoDB Atlas, web uygulamaları için yüksek performanslı ve ölçeklenebilir bir veritabanı çözümü sunar.
- Mobil Uygulamalar: Mobil uygulamalar için hızlı ve güvenilir bir veritabanı hizmeti sağlar.
- IoT (Nesnelerin İnterneti): Büyük miktarda veriyi gerçek zamanlı olarak işlemek için idealdir.
- Büyük Veri Analitiği: Veri gölü ve gerçek zamanlı analiz özellikleri ile büyük veri projelerinde kullanılabilir.
- E-ticaret: Yüksek trafikli e-ticaret siteleri için ölçeklenebilir ve güvenilir bir çözüm sunar.
CRUD Operasyonları
Insert işlemleri (insertOne, insertMany)
1. insertOne
Metodu
insertOne
metodu, MongoDB koleksiyonuna tek bir belge eklemek için kullanılır. Bu metodun temel amacı, belirtilen koleksiyona yalnızca bir belge eklemektir.
Sözel Açıklama:
- Koleksiyon (Collection): MongoDB’de veriler koleksiyonlar içinde saklanır. Koleksiyon, SQL’deki tablolara benzer.
- Belge (Document): MongoDB’de veriler JSON benzeri BSON formatında saklanır. Her bir kayıt bir belge olarak adlandırılır.
- insertOne: Bu metod, belirtilen koleksiyona tek bir belge ekler. Eğer koleksiyon daha önce yoksa, MongoDB otomatik olarak bu koleksiyonu oluşturur.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Eklenecek belge
const user = {
name: "Ahmet Yılmaz",
age: 30,
email: "ahmet.yilmaz@example.com"
};
// insertOne metodu ile belge ekleme
const result = await collection.insertOne(user);
console.log(`Eklenen belge ID'si: ${result.insertedId}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
insertOne
metodu, bir belgeyi koleksiyona ekler ve eklenen belgenin_id
değerini döndürür.- Eğer belge içinde
_id
alanı belirtilmemişse, MongoDB otomatik olarak birObjectId
oluşturur.
2. insertMany
Metodu
insertMany
metodu, MongoDB koleksiyonuna birden fazla belge eklemek için kullanılır. Bu metod, bir dizi belgeyi tek bir işlemde koleksiyona ekler.
Sözel Açıklama:
- insertMany: Bu metod, belirtilen koleksiyona birden fazla belge ekler. Tüm belgeler tek bir işlemde eklenir, bu da performans açısından avantaj sağlar.
- Dizi (Array):
insertMany
metodu, bir dizi içinde birden fazla belge alır ve bu belgeleri koleksiyona ekler.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Eklenecek belgeler dizisi
const users = [
{ name: "Mehmet Demir", age: 25, email: "mehmet.demir@example.com" },
{ name: "Ayşe Kaya", age: 28, email: "ayse.kaya@example.com" },
{ name: "Fatma Şahin", age: 35, email: "fatma.sahin@example.com" }
];
// insertMany metodu ile belgeleri ekleme
const result = await collection.insertMany(users);
console.log(`Eklenen belge sayısı: ${result.insertedCount}`);
console.log(`Eklenen belge ID'leri: ${result.insertedIds}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
insertMany
metodu, bir dizi içinde birden fazla belgeyi koleksiyona ekler.- Her bir belge için
_id
alanı otomatik olarak oluşturulur (eğer belirtilmemişse). insertedCount
alanı, kaç belgenin eklendiğini gösterir.insertedIds
alanı, eklenen belgelerin_id
değerlerini içeren bir nesne döndürür.
Hata Yönetimi ve İpuçları
- Hata Yönetimi: Eğer eklenmek istenen belgelerden herhangi biri
_id
alanına sahipse ve bu_id
koleksiyonda zaten varsa, MongoDB bir hata fırlatır. Bu durumda,try-catch
blokları kullanarak hataları yönetebilirsiniz. - Performans:
insertMany
metodu, tek bir işlemde birden fazla belge eklediği için, tek tekinsertOne
kullanmaktan daha performanslıdır. - Atomicity: MongoDB’de
insertOne
veinsertMany
işlemleri atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur. Bu, veri tutarlılığı açısından önemlidir.
Find ve Query operasyonları
1. find
Metodu
find
metodu, MongoDB koleksiyonundaki belgeleri sorgulamak için kullanılır. Bu metod, belirtilen sorgu kriterlerine uyan belgeleri bir cursor (işaretçi) olarak döndürür.
Sözel Açıklama:
- Cursor:
find
metodu, sorgu sonucunda bir cursor döndürür. Bu cursor, sorgu sonuçlarını üzerinde gezinebileceğiniz bir işaretçidir. - Sorgu Kriterleri:
find
metodu, belirli kriterlere göre belgeleri filtrelemek için kullanılır. Eğer herhangi bir kriter belirtilmezse, koleksiyondaki tüm belgeleri döndürür. - Projection:
find
metodu, döndürülen belgelerin hangi alanlarını istediğinizi belirlemenize olanak tanır. Bu, performansı artırmak ve gereksiz veri transferini önlemek için kullanışlıdır.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Tüm belgeleri sorgula
const cursor = collection.find({});
// Sorgu sonuçlarını yazdır
await cursor.forEach(doc => console.log(doc));
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
find
metodu, herhangi bir kriter belirtilmezse koleksiyondaki tüm belgeleri döndürür.cursor.forEach
metodu, sorgu sonuçlarını tek tek işlemek için kullanılır.
2. Sorgu Kriterleri
MongoDB’de sorgu kriterleri, belgeleri filtrelemek için kullanılır. Bu kriterler, SQL’deki WHERE
koşullarına benzer.
Sözel Açıklama:
- Eşitlik Sorguları: Belirli bir alanın belirli bir değere eşit olmasını sağlar.
- Karşılaştırma Operatörleri:
$gt
,$lt
,$gte
,$lte
gibi operatörler, belirli bir alanın belirli bir değerden büyük, küçük, büyük eşit veya küçük eşit olmasını sağlar. - Mantıksal Operatörler:
$and
,$or
,$not
,$nor
gibi operatörler, birden fazla koşulu birleştirmek için kullanılır.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Yaşı 25'ten büyük olan kullanıcıları sorgula
const query = { age: { $gt: 25 } };
const cursor = collection.find(query);
// Sorgu sonuçlarını yazdır
await cursor.forEach(doc => console.log(doc));
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
{ age: { $gt: 25 } }
sorgusu,age
alanı 25’ten büyük olan belgeleri döndürür.$gt
operatörü, “greater than” (büyüktür) anlamına gelir.
3. Projection
Projection, sorgu sonuçlarında hangi alanların döndürüleceğini belirlemek için kullanılır. Bu, performansı artırmak ve gereksiz veri transferini önlemek için kullanışlıdır.
Sözel Açıklama:
- Projection:
find
metodunun ikinci parametresi olarak kullanılır.1
değeri, belirtilen alanın döndürülmesini sağlar,0
değeri ise belirtilen alanın döndürülmemesini sağlar.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Sadece name ve email alanlarını döndür
const projection = { name: 1, email: 1, _id: 0 };
const cursor = collection.find({}, { projection });
// Sorgu sonuçlarını yazdır
await cursor.forEach(doc => console.log(doc));
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
{ name: 1, email: 1, _id: 0 }
projection’ı, sadecename
veemail
alanlarını döndürür ve_id
alanını döndürmez.
4. Sıralama ve Limit
Sorgu sonuçlarını sıralamak ve belirli bir sayıda belge döndürmek için sort
ve limit
metotları kullanılır.
Sözel Açıklama:
- Sıralama:
sort
metodu, sorgu sonuçlarını belirli bir alana göre sıralamak için kullanılır.1
artan sıralama,-1
azalan sıralama anlamına gelir. - Limit:
limit
metodu, sorgu sonuçlarının belirli bir sayıda döndürülmesini sağlar.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Yaşa göre artan sırala ve ilk 5 belgeyi döndür
const cursor = collection.find({}).sort({ age: 1 }).limit(5);
// Sorgu sonuçlarını yazdır
await cursor.forEach(doc => console.log(doc));
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
sort({ age: 1 })
sorgusu, sonuçlarıage
alanına göre artan sırada sıralar.limit(5)
sorgusu, sadece ilk 5 belgeyi döndürür.
Update işlemleri (updateOne, updateMany, replaceOne)
Elbette! MongoDB’de CRUD (Create, Read, Update, Delete) operasyonlarından “Update” (Güncelleme) işlemleri, veritabanındaki mevcut belgeleri değiştirmek için kullanılır. Bu işlemler genellikle updateOne
, updateMany
ve replaceOne
metotları ile gerçekleştirilir. Şimdi bu metotları derinlemesine inceleyelim.
1. updateOne
Metodu
updateOne
metodu, MongoDB koleksiyonundaki belirli bir kriterle eşleşen ilk belgeyi güncellemek için kullanılır. Eğer birden fazla belge kriterle eşleşiyorsa, sadece ilk bulunan belge güncellenir.
Sözel Açıklama:
- Kriter: Güncellenecek belgeyi bulmak için kullanılan sorgu kriterleri.
- Güncelleme Operatörleri: Belgeyi nasıl güncelleyeceğinizi belirleyen operatörler. Örneğin,
$set
belirli bir alanı günceller,$inc
bir alanın değerini artırır. - Atomicity:
updateOne
işlemi atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Güncellenecek belgeyi bulmak için kriter
const filter = { name: "Ahmet Yılmaz" };
// Güncelleme operatörü
const update = { $set: { age: 31 } };
// updateOne metodu ile belgeyi güncelle
const result = await collection.updateOne(filter, update);
console.log(`Güncellenen belge sayısı: ${result.modifiedCount}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
filter
kriteri,name
alanı “Ahmet Yılmaz” olan belgeyi bulur.update
operatörü,age
alanını 31 olarak günceller.result.modifiedCount
, güncellenen belge sayısını döndürür.
2. updateMany
Metodu
updateMany
metodu, MongoDB koleksiyonundaki belirli bir kriterle eşleşen tüm belgeleri güncellemek için kullanılır.
Sözel Açıklama:
- Kriter: Güncellenecek belgeleri bulmak için kullanılan sorgu kriterleri.
- Güncelleme Operatörleri: Belgeyi nasıl güncelleyeceğinizi belirleyen operatörler. Örneğin,
$set
belirli bir alanı günceller,$inc
bir alanın değerini artırır. - Atomicity:
updateMany
işlemi atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Güncellenecek belgeleri bulmak için kriter
const filter = { age: { $lt: 30 } };
// Güncelleme operatörü
const update = { $set: { status: "genç" } };
// updateMany metodu ile belgeleri güncelle
const result = await collection.updateMany(filter, update);
console.log(`Güncellenen belge sayısı: ${result.modifiedCount}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
filter
kriteri,age
alanı 30’dan küçük olan belgeleri bulur.update
operatörü,status
alanını “genç” olarak günceller.result.modifiedCount
, güncellenen belge sayısını döndürür.
3. replaceOne
Metodu
replaceOne
metodu, MongoDB koleksiyonundaki belirli bir kriterle eşleşen ilk belgeyi tamamen yeni bir belge ile değiştirmek için kullanılır. Bu metod, belgeyi tamamen değiştirir, yani sadece belirli alanları güncellemez.
Sözel Açıklama:
- Kriter: Değiştirilecek belgeyi bulmak için kullanılan sorgu kriterleri.
- Yeni Belge: Eski belgenin yerine geçecek yeni belge.
- Atomicity:
replaceOne
işlemi atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Değiştirilecek belgeyi bulmak için kriter
const filter = { name: "Ahmet Yılmaz" };
// Yeni belge
const replacement = {
name: "Ahmet Yılmaz",
age: 32,
email: "ahmet.yilmaz@example.com",
status: "aktif"
};
// replaceOne metodu ile belgeyi değiştir
const result = await collection.replaceOne(filter, replacement);
console.log(`Değiştirilen belge sayısı: ${result.modifiedCount}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
filter
kriteri,name
alanı “Ahmet Yılmaz” olan belgeyi bulur.replacement
belgesi, eski belgenin yerine geçecek yeni belgedir.result.modifiedCount
, değiştirilen belge sayısını döndürür.
Hata Yönetimi ve İpuçları
- Hata Yönetimi: Eğer güncelleme işlemi sırasında bir hata oluşursa,
try-catch
blokları kullanarak hataları yönetebilirsiniz. - Performans:
updateMany
metodu, tek bir işlemde birden fazla belgeyi güncellediği için, tek tekupdateOne
kullanmaktan daha performanslıdır. - Atomicity: MongoDB’de
updateOne
,updateMany
vereplaceOne
işlemleri atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur. Bu, veri tutarlılığı açısından önemlidir.
Delete işlemleri (deleteOne, deleteMany)
1. deleteOne
Metodu
deleteOne
metodu, MongoDB koleksiyonundaki belirli bir kriterle eşleşen ilk belgeyi silmek için kullanılır. Eğer birden fazla belge kriterle eşleşiyorsa, sadece ilk bulunan belge silinir.
Sözel Açıklama:
- Kriter: Silinecek belgeyi bulmak için kullanılan sorgu kriterleri.
- Atomicity:
deleteOne
işlemi atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur. - Sonuç: İşlem sonucunda silinen belge sayısı döndürülür.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Silinecek belgeyi bulmak için kriter
const filter = { name: "Ahmet Yılmaz" };
// deleteOne metodu ile belgeyi sil
const result = await collection.deleteOne(filter);
console.log(`Silinen belge sayısı: ${result.deletedCount}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
filter
kriteri,name
alanı “Ahmet Yılmaz” olan belgeyi bulur.deleteOne
metodu, bu belgeyi siler.result.deletedCount
, silinen belge sayısını döndürür. Eğer belge bulunamazsa, bu değer0
olur.
2. deleteMany
Metodu
deleteMany
metodu, MongoDB koleksiyonundaki belirli bir kriterle eşleşen tüm belgeleri silmek için kullanılır.
Sözel Açıklama:
- Kriter: Silinecek belgeleri bulmak için kullanılan sorgu kriterleri.
- Atomicity:
deleteMany
işlemi atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur. - Sonuç: İşlem sonucunda silinen belge sayısı döndürülür.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Silinecek belgeleri bulmak için kriter
const filter = { status: "pasif" };
// deleteMany metodu ile belgeleri sil
const result = await collection.deleteMany(filter);
console.log(`Silinen belge sayısı: ${result.deletedCount}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
filter
kriteri,status
alanı “pasif” olan belgeleri bulur.deleteMany
metodu, bu belgeleri siler.result.deletedCount
, silinen belge sayısını döndürür. Eğer belge bulunamazsa, bu değer0
olur.
Hata Yönetimi ve İpuçları
- Hata Yönetimi: Eğer silme işlemi sırasında bir hata oluşursa,
try-catch
blokları kullanarak hataları yönetebilirsiniz. - Performans:
deleteMany
metodu, tek bir işlemde birden fazla belgeyi sildiği için, tek tekdeleteOne
kullanmaktan daha performanslıdır. - Atomicity: MongoDB’de
deleteOne
vedeleteMany
işlemleri atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur. Bu, veri tutarlılığı açısından önemlidir.
3. findOneAndDelete
Metodu
findOneAndDelete
metodu, belirli bir kriterle eşleşen ilk belgeyi siler ve silinen belgeyi döndürür. Bu metod, silinen belgeyi geri döndürmek istediğiniz durumlarda kullanışlıdır.
Sözel Açıklama:
- Kriter: Silinecek belgeyi bulmak için kullanılan sorgu kriterleri.
- Sonuç: Silinen belgeyi döndürür.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Silinecek belgeyi bulmak için kriter
const filter = { name: "Mehmet Demir" };
// findOneAndDelete metodu ile belgeyi sil ve silinen belgeyi döndür
const result = await collection.findOneAndDelete(filter);
console.log(`Silinen belge: ${JSON.stringify(result.value)}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
filter
kriteri,name
alanı “Mehmet Demir” olan belgeyi bulur.findOneAndDelete
metodu, bu belgeyi siler ve silinen belgeyi döndürür.result.value
, silinen belgeyi içerir. Eğer belge bulunamazsa, bu değernull
olur.
Bulk write operasyonları
1. Bulk Write Nedir?
Bulk Write, MongoDB’de birden fazla insert, update, delete ve replace işlemini tek bir istekte gerçekleştirmek için kullanılan bir yöntemdir. Bu yöntem, özellikle büyük veri kümeleri üzerinde çalışırken performans avantajı sağlar.
Sözel Açıklama:
- Toplu İşlemler: Bulk Write, birden fazla işlemi tek bir istekte gerçekleştirir. Bu işlemler insert, update, delete ve replace işlemlerini içerebilir.
- Performans: Bulk Write, ağ üzerindeki yükü azaltır ve işlemleri daha hızlı gerçekleştirir.
- Atomicity: Bulk Write işlemleri, belirli bir sıraya göre gerçekleştirilir ve her bir işlem atomiktir.
2. Bulk Write Operasyonları
MongoDB’de Bulk Write işlemleri, aşağıdaki operasyon türlerini destekler:
- insertOne: Tek bir belge ekler.
- updateOne: Tek bir belgeyi günceller.
- updateMany: Birden fazla belgeyi günceller.
- deleteOne: Tek bir belgeyi siler.
- deleteMany: Birden fazla belgeyi siler.
- replaceOne: Tek bir belgeyi değiştirir.
3. Bulk Write Kullanımı
Bulk Write işlemleri, bulkWrite
metodu kullanılarak gerçekleştirilir. Bu metod, bir dizi işlem alır ve bu işlemleri sırayla gerçekleştirir.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Bulk Write işlemleri
const operations = [
{ insertOne: { document: { name: "Ahmet Yılmaz", age: 30, email: "ahmet.yilmaz@example.com" } } },
{ updateOne: { filter: { name: "Mehmet Demir" }, update: { $set: { age: 31 } } } },
{ deleteOne: { filter: { name: "Ayşe Kaya" } } },
{ replaceOne: { filter: { name: "Fatma Şahin" }, replacement: { name: "Fatma Şahin", age: 35, email: "fatma.sahin@example.com", status: "aktif" } } }
];
// bulkWrite metodu ile işlemleri gerçekleştir
const result = await collection.bulkWrite(operations);
console.log(`İşlem sonuçları: ${JSON.stringify(result)}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
operations
dizisi, gerçekleştirilecek işlemleri içerir. Her bir işlem, bir operasyon türü ve bu operasyonun parametrelerini içerir.bulkWrite
metodu, bu işlemleri sırayla gerçekleştirir ve sonuçları döndürür.result
nesnesi, gerçekleştirilen işlemlerin sonuçlarını içerir. Örneğin,insertedCount
,modifiedCount
,deletedCount
gibi alanlar bulunur.
4. Bulk Write İşlem Sonuçları
Bulk Write işlemleri sonucunda, gerçekleştirilen işlemlerin detaylarını içeren bir nesne döndürülür. Bu nesne, aşağıdaki alanları içerebilir:
- insertedCount: Eklenen belge sayısı.
- matchedCount: Eşleşen belge sayısı (update ve replace işlemleri için).
- modifiedCount: Güncellenen belge sayısı (update ve replace işlemleri için).
- deletedCount: Silinen belge sayısı.
- upsertedCount: Upsert işlemi sonucunda eklenen belge sayısı.
- upsertedIds: Upsert işlemi sonucunda eklenen belgelerin
_id
değerleri.
5. Bulk Write İşlemlerinde Sıra ve Atomicity
Bulk Write işlemleri, belirtilen sıraya göre gerçekleştirilir. Her bir işlem atomiktir, yani ya tamamen başarılı olur ya da tamamen başarısız olur. Ancak, tüm Bulk Write işlemi atomik değildir. Yani, bir işlem başarısız olsa bile, diğer işlemler gerçekleştirilmeye devam eder.
Kod Örneği:
const { MongoClient } = require('mongodb');
async function run() {
const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('testdb'); // Veritabanı adı
const collection = database.collection('users'); // Koleksiyon adı
// Bulk Write işlemleri
const operations = [
{ insertOne: { document: { name: "Ahmet Yılmaz", age: 30, email: "ahmet.yilmaz@example.com" } } },
{ updateOne: { filter: { name: "Mehmet Demir" }, update: { $set: { age: 31 } } } },
{ deleteOne: { filter: { name: "Ayşe Kaya" } } },
{ replaceOne: { filter: { name: "Fatma Şahin" }, replacement: { name: "Fatma Şahin", age: 35, email: "fatma.sahin@example.com", status: "aktif" } } }
];
// bulkWrite metodu ile işlemleri gerçekleştir
const result = await collection.bulkWrite(operations, { ordered: false });
console.log(`İşlem sonuçları: ${JSON.stringify(result)}`);
} finally {
await client.close();
}
}
run().catch(console.dir);
Açıklama:
ordered: false
parametresi, işlemlerin sırayla değil, mümkün olduğunca paralel olarak gerçekleştirilmesini sağlar. Bu, bir işlem başarısız olsa bile diğer işlemlerin devam etmesini sağlar.ordered: true
(varsayılan) parametresi, işlemlerin belirtilen sırayla gerçekleştirilmesini sağlar. Bir işlem başarısız olursa, diğer işlemler durdurulur.
Gelişmiş Sorgulama
Query operatörleri ($eq, $gt, $lt, $in vb.)
1. $eq (Eşitlik Operatörü)
$eq
operatörü, belirli bir alanın belirli bir değere eşit olup olmadığını kontrol etmek için kullanılır. Aslında, MongoDB’de bir alanı sorgularken direkt olarak değer belirtmek $eq
kullanmakla aynı anlama gelir.
Örnek:
db.collection.find({ age: 25 });
Bu sorgu, age
alanı 25 olan tüm belgeleri döndürür. Aynı sorguyu $eq
operatörü ile şu şekilde yazabiliriz:
db.collection.find({ age: { $eq: 25 } });
2. $gt (Büyüktür Operatörü)
$gt
operatörü, belirli bir alanın belirli bir değerden büyük olup olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $gt: 25 } });
Bu sorgu, age
alanı 25’ten büyük olan tüm belgeleri döndürür.
3. $lt (Küçüktür Operatörü)
$lt
operatörü, belirli bir alanın belirli bir değerden küçük olup olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $lt: 30 } });
Bu sorgu, age
alanı 30’dan küçük olan tüm belgeleri döndürür.
4. $gte (Büyük Eşittir Operatörü)
$gte
operatörü, belirli bir alanın belirli bir değerden büyük veya eşit olup olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $gte: 25 } });
Bu sorgu, age
alanı 25 veya daha büyük olan tüm belgeleri döndürür.
5. $lte (Küçük Eşittir Operatörü)
$lte
operatörü, belirli bir alanın belirli bir değerden küçük veya eşit olup olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $lte: 30 } });
Bu sorgu, age
alanı 30 veya daha küçük olan tüm belgeleri döndürür.
6. $in (İçinde Operatörü)
$in
operatörü, belirli bir alanın belirli bir değer listesindeki herhangi bir değere eşit olup olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $in: [25, 30, 35] } });
Bu sorgu, age
alanı 25, 30 veya 35 olan tüm belgeleri döndürür.
7. $nin (İçinde Değil Operatörü)
$nin
operatörü, belirli bir alanın belirli bir değer listesindeki hiçbir değere eşit olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $nin: [25, 30, 35] } });
Bu sorgu, age
alanı 25, 30 veya 35 olmayan tüm belgeleri döndürür.
8. $ne (Eşit Değil Operatörü)
$ne
operatörü, belirli bir alanın belirli bir değere eşit olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $ne: 25 } });
Bu sorgu, age
alanı 25 olmayan tüm belgeleri döndürür.
9. $and (Ve Operatörü)
$and
operatörü, birden fazla koşulun hepsinin aynı anda sağlanması gereken durumlarda kullanılır.
Örnek:
db.collection.find({ $and: [{ age: { $gt: 25 } }, { age: { $lt: 30 } }] });
Bu sorgu, age
alanı 25’ten büyük ve 30’dan küçük olan tüm belgeleri döndürür.
10. $or (Veya Operatörü)
$or
operatörü, birden fazla koşuldan herhangi birinin sağlanması gereken durumlarda kullanılır.
Örnek:
db.collection.find({ $or: [{ age: 25 }, { age: 30 }] });
Bu sorgu, age
alanı 25 veya 30 olan tüm belgeleri döndürür.
11. $not (Değil Operatörü)
$not
operatörü, belirli bir koşulun sağlanmadığı durumlarda kullanılır.
Örnek:
db.collection.find({ age: { $not: { $gt: 25 } } });
Bu sorgu, age
alanı 25’ten büyük olmayan tüm belgeleri döndürür.
12. $exists (Var Olma Operatörü)
$exists
operatörü, belirli bir alanın belgede var olup olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $exists: true } });
Bu sorgu, age
alanı olan tüm belgeleri döndürür.
13. $type (Tip Operatörü)
$type
operatörü, belirli bir alanın belirli bir tipte olup olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ age: { $type: "number" } });
Bu sorgu, age
alanı sayı tipinde olan tüm belgeleri döndürür.
14. $regex (Regex Operatörü)
$regex
operatörü, belirli bir alanın belirli bir regex ifadesine uyup uymadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ name: { $regex: /^J/ } });
Bu sorgu, name
alanı “J” harfi ile başlayan tüm belgeleri döndürür.
15. $all (Tümü Operatörü)
$all
operatörü, bir dizi alanın belirli bir değer listesindeki tüm değerleri içerip içermediğini kontrol etmek için kullanılır.
Örnek:
db.collection.find({ tags: { $all: ["mongodb", "database"] } });
Bu sorgu, tags
alanı hem “mongodb” hem de “database” değerlerini içeren tüm belgeleri döndürür.
16. $elemMatch (Dizi Elemanı Eşleştirme Operatörü)
$elemMatch
operatörü, bir dizi alanın içindeki elemanların belirli bir koşulu sağlayıp sağlamadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ scores: { $elemMatch: { $gt: 80, $lt: 90 } } });
Bu sorgu, scores
alanı içinde 80’den büyük ve 90’dan küçük olan en az bir eleman bulunan tüm belgeleri döndürür.
17. $size (Dizi Boyutu Operatörü)
$size
operatörü, bir dizi alanın belirli bir boyuta sahip olup olmadığını kontrol etmek için kullanılır.
Örnek:
db.collection.find({ tags: { $size: 3 } });
Bu sorgu, tags
alanı tam olarak 3 elemana sahip olan tüm belgeleri döndürür.
Mantıksal operatörler ($and, $or, $not)
1. $and Operatörü
Ne İşe Yarar?
$and
operatörü, birden fazla koşulun hepsinin aynı anda sağlanması gereken durumlarda kullanılır. Yani, belirtilen tüm koşulların doğru olması gerekir.
Sözdizimi:
{ $and: [ { koşul1 }, { koşul2 }, ... ] }
Örnek:
Aşağıdaki örnekte, age
alanı 25’ten büyük ve city
alanı “İstanbul” olan belgeler aranıyor:
db.collection.find({
$and: [
{ age: { $gt: 25 } },
{ city: "İstanbul" }
]
});
Not:
- MongoDB’de birden fazla koşulu virgülle ayırarak yazmak,
$and
operatörü kullanmakla aynı anlama gelir. Örneğin:
db.collection.find({ age: { $gt: 25 }, city: "İstanbul" });
Bu sorgu da yukarıdaki $and
örneğiyle aynı sonucu verir.
2. $or Operatörü
Ne İşe Yarar?
$or
operatörü, birden fazla koşuldan herhangi birinin sağlanması gereken durumlarda kullanılır. Yani, belirtilen koşullardan en az birinin doğru olması yeterlidir.
Sözdizimi:
{ $or: [ { koşul1 }, { koşul2 }, ... ] }
Örnek:
Aşağıdaki örnekte, age
alanı 25 veya city
alanı “Ankara” olan belgeler aranıyor:
db.collection.find({
$or: [
{ age: 25 },
{ city: "Ankara" }
]
});
Kullanım Senaryosu:
- Örneğin, bir kullanıcı veritabanında yaşları 25 olan veya Ankara’da yaşayan kullanıcıları bulmak istiyorsanız, bu operatörü kullanabilirsiniz.
3. $not Operatörü
Ne İşe Yarar?
$not
operatörü, belirli bir koşulun sağlanmadığı durumlarda kullanılır. Yani, belirtilen koşulun tersini arar.
Sözdizimi:
{ field: { $not: { koşul } } }
Örnek:
Aşağıdaki örnekte, age
alanı 25 olmayan belgeler aranıyor:
db.collection.find({
age: { $not: { $eq: 25 } }
});
Not:
$not
operatörü, genellikle diğer operatörlerle birlikte kullanılır. Örneğin,$gt
veya$regex
gibi operatörlerle birleştirilebilir.
4. $nor Operatörü
Ne İşe Yarar?
$nor
operatörü, belirtilen koşulların hiçbirinin sağlanmadığı durumlarda kullanılır. Yani, tüm koşulların yanlış olması gerekir.
Sözdizimi:
{ $nor: [ { koşul1 }, { koşul2 }, ... ] }
Örnek:
Aşağıdaki örnekte, age
alanı 25 veya city
alanı “İstanbul” olmayan belgeler aranıyor:
db.collection.find({
$nor: [
{ age: 25 },
{ city: "İstanbul" }
]
});
Kullanım Senaryosu:
- Örneğin, belirli bir yaşta olmayan ve belirli bir şehirde yaşamayan kullanıcıları bulmak istiyorsanız, bu operatörü kullanabilirsiniz.
5. Mantıksal Operatörlerin Birlikte Kullanımı
Mantıksal operatörler, birbirleriyle birlikte kullanılarak daha karmaşık sorgular oluşturulabilir. Örneğin, $and
ve $or
operatörlerini bir arada kullanabilirsiniz.
Örnek:
Aşağıdaki örnekte, age
alanı 25’ten büyük ve (city
alanı “İstanbul” veya “Ankara”) olan belgeler aranıyor:
db.collection.find({
$and: [
{ age: { $gt: 25 } },
{
$or: [
{ city: "İstanbul" },
{ city: "Ankara" }
]
}
]
});
Açıklama:
- Bu sorgu, yaşı 25’ten büyük olan ve İstanbul veya Ankara’da yaşayan kullanıcıları bulur.
6. $and ve $or Operatörlerinin Farkı
- $and: Tüm koşulların aynı anda sağlanması gerekir.
- $or: Koşullardan en az birinin sağlanması yeterlidir.
Örnek Karşılaştırma:
$and
örneği:
db.collection.find({
$and: [
{ age: { $gt: 25 } },
{ city: "İstanbul" }
]
});
Bu sorgu, yaşı 25’ten büyük ve İstanbul’da yaşayan kullanıcıları bulur.
$or
örneği:
db.collection.find({
$or: [
{ age: { $gt: 25 } },
{ city: "İstanbul" }
]
});
Bu sorgu, yaşı 25’ten büyük veya İstanbul’da yaşayan kullanıcıları bulur.
7. $not Operatörünün Diğer Operatörlerle Kullanımı
$not
operatörü, diğer operatörlerle birlikte kullanılarak daha spesifik sorgular oluşturulabilir.
Örnek:
Aşağıdaki örnekte, age
alanı 25’ten büyük olmayan belgeler aranıyor:
db.collection.find({
age: { $not: { $gt: 25 } }
});
Array operatörleri ($all, $elemMatch)
1. $all Operatörü
Ne İşe Yarar?
$all
operatörü, bir dizi alanın belirli bir değer listesindeki tüm değerleri içerip içermediğini kontrol etmek için kullanılır. Yani, dizi içinde belirtilen tüm değerlerin bulunması gerekir.
Sözdizimi:
{ field: { $all: [ değer1, değer2, ... ] } }
Örnek:
Aşağıdaki örnekte, tags
alanı hem “mongodb” hem de “database” değerlerini içeren belgeler aranıyor:
db.collection.find({
tags: { $all: ["mongodb", "database"] }
});
Açıklama:
- Bu sorgu,
tags
dizisinde hem “mongodb” hem de “database” değerlerinin bulunduğu belgeleri döndürür. - Dizide bu değerlerin sırası önemli değildir.
Kullanım Senaryosu:
- Örneğin, bir blog yazıları koleksiyonunda belirli etiketlere sahip yazıları bulmak istiyorsanız, bu operatörü kullanabilirsiniz.
2. $elemMatch Operatörü
Ne İşe Yarar?
$elemMatch
operatörü, bir dizi alanın içindeki elemanların belirli bir koşulu sağlayıp sağlamadığını kontrol etmek için kullanılır. Bu operatör, özellikle dizilerdeki nesneler (object) üzerinde sorgulama yaparken kullanışlıdır.
Sözdizimi:
{ field: { $elemMatch: { koşul1, koşul2, ... } } }
Örnek 1: Basit Kullanım
Aşağıdaki örnekte, scores
dizisinde 80’den büyük ve 90’dan küçük olan en az bir eleman bulunan belgeler aranıyor:
db.collection.find({
scores: { $elemMatch: { $gt: 80, $lt: 90 } }
});
Açıklama:
- Bu sorgu,
scores
dizisinde 80’den büyük ve 90’dan küçük olan en az bir eleman bulunan belgeleri döndürür.
Örnek 2: Nesneler Üzerinde Sorgulama
Aşağıdaki örnekte, students
dizisinde name
alanı “Ali” ve score
alanı 80’den büyük olan en az bir nesne bulunan belgeler aranıyor:
db.collection.find({
students: {
$elemMatch: {
name: "Ali",
score: { $gt: 80 }
}
}
});
Açıklama:
- Bu sorgu,
students
dizisindename
alanı “Ali” vescore
alanı 80’den büyük olan en az bir nesne bulunan belgeleri döndürür.
Kullanım Senaryosu:
- Örneğin, bir sınav sonuçları koleksiyonunda belirli bir öğrencinin belirli bir puan aralığında sonuçlarını bulmak istiyorsanız, bu operatörü kullanabilirsiniz.
3. $all ve $elemMatch Arasındaki Fark
- $all: Dizinin belirli bir değer listesindeki tüm değerleri içermesini kontrol eder.
- $elemMatch: Dizinin içindeki elemanların belirli bir koşulu sağlamasını kontrol eder.
Örnek Karşılaştırma:
$all
örneği:
db.collection.find({
tags: { $all: ["mongodb", "database"] }
});
Bu sorgu, tags
dizisinde hem “mongodb” hem de “database” değerlerinin bulunduğu belgeleri döndürür.
$elemMatch
örneği:
db.collection.find({
scores: { $elemMatch: { $gt: 80, $lt: 90 } }
});
Bu sorgu, scores
dizisinde 80’den büyük ve 90’dan küçük olan en az bir eleman bulunan belgeleri döndürür.
4. $all ve $elemMatch Operatörlerinin Birlikte Kullanımı
Bu iki operatör, birlikte kullanılarak daha karmaşık sorgular oluşturulabilir.
Örnek:
Aşağıdaki örnekte, tags
dizisinde hem “mongodb” hem de “database” değerlerinin bulunduğu ve scores
dizisinde 80’den büyük ve 90’dan küçük olan en az bir eleman bulunan belgeler aranıyor:
db.collection.find({
$and: [
{ tags: { $all: ["mongodb", "database"] } },
{ scores: { $elemMatch: { $gt: 80, $lt: 90 } } }
]
});
Açıklama:
- Bu sorgu, hem
tags
dizisinde belirli değerlerin bulunduğu hem descores
dizisinde belirli bir puan aralığına sahip olan belgeleri döndürür.
5. $size Operatörü (Bonus)
$size
operatörü, bir dizi alanın belirli bir boyuta sahip olup olmadığını kontrol etmek için kullanılır. Bu operatör, dizilerin uzunluğuna göre filtreleme yapmanıza olanak tanır.
Sözdizimi:
{ field: { $size: boyut } }
Örnek:
Aşağıdaki örnekte, tags
dizisinin tam olarak 3 elemana sahip olduğu belgeler aranıyor:
db.collection.find({
tags: { $size: 3 }
});
Kullanım Senaryosu:
- Örneğin, belirli sayıda etikete sahip blog yazılarını bulmak istiyorsanız, bu operatörü kullanabilirsiniz.
Regex kullanımı
1. Regex Nedir?
Regex (regular expression), metinlerde belirli bir deseni ifade etmek için kullanılan bir notasyondur. Örneğin:
^J
: “J” harfi ile başlayan metinler..*test$
: “test” ile biten metinler.[0-9]{3}
: Tam olarak 3 rakamdan oluşan metinler.
MongoDB, regex’i metin alanları üzerinde sorgulama yaparken kullanmanıza olanak tanır.
2. Regex Sözdizimi
MongoDB’de regex kullanmanın iki yolu vardır:
a) JavaScript Regex Sözdizimi
{ field: /pattern/options }
pattern
: Aranacak regex deseni.options
: Regex seçenekleri (örneğin,i
büyük/küçük harf duyarsız,m
çok satırlı mod).
b) $regex Operatörü
{ field: { $regex: "pattern", $options: "options" } }
$regex
: Aranacak regex deseni.$options
: Regex seçenekleri.
3. Regex Seçenekleri (Options)
i
: Büyük/küçük harf duyarsız (case-insensitive).m
: Çok satırlı mod (multiline).^
ve$
işaretleri satır başını ve sonunu ifade eder.x
: Boşluk karakterlerini yok sayar.s
: Nokta (.
) karakterinin yeni satır (\n
) dahil tüm karakterlerle eşleşmesini sağlar.
4. Regex Kullanım Örnekleri
a) Basit Regex Kullanımı
Aşağıdaki örnekte, name
alanı “Ali” ile başlayan belgeler aranıyor:
db.collection.find({ name: /^Ali/ });
Veya $regex
operatörü ile:
db.collection.find({ name: { $regex: "^Ali" } });
b) Büyük/Küçük Harf Duyarsız Arama
Aşağıdaki örnekte, name
alanı “ali” ile başlayan belgeler aranıyor (büyük/küçük harf duyarsız):
db.collection.find({ name: /^ali/i });
Veya $regex
operatörü ile:
db.collection.find({ name: { $regex: "^ali", $options: "i" } });
c) Belirli Bir Desenle Eşleşen Metinler
Aşağıdaki örnekte, email
alanı “.com” ile biten belgeler aranıyor:
db.collection.find({ email: /\.com$/ });
Veya $regex
operatörü ile:
db.collection.find({ email: { $regex: "\\.com$" } });
d) Rakam İçeren Metinler
Aşağıdaki örnekte, description
alanı en az bir rakam içeren belgeler aranıyor:
db.collection.find({ description: /[0-9]/ });
Veya $regex
operatörü ile:
db.collection.find({ description: { $regex: "[0-9]" } });
e) Belirli Bir Uzunluktaki Metinler
Aşağıdaki örnekte, username
alanı tam olarak 5 karakterden oluşan belgeler aranıyor:
db.collection.find({ username: /^.{5}$/ });
Veya $regex
operatörü ile:
db.collection.find({ username: { $regex: "^.{5}$" } });
5. Regex ve Diğer Operatörlerle Birlikte Kullanım
Regex, diğer MongoDB operatörleriyle birlikte kullanılarak daha karmaşık sorgular oluşturulabilir.
Örnek:
Aşağıdaki örnekte, name
alanı “A” ile başlayan ve age
alanı 25’ten büyük olan belgeler aranıyor:
db.collection.find({
name: { $regex: "^A" },
age: { $gt: 25 }
});
6. Regex Performansı
- Regex sorguları, özellikle büyük veri kümelerinde performans açısından maliyetli olabilir.
- Regex sorguları, index’leri kullanmaz (büyük/küçük harf duyarsız aramalar hariç). Bu nedenle, büyük koleksiyonlarda dikkatli kullanılmalıdır.
- Performansı artırmak için, regex sorgularını mümkün olduğunca spesifik hale getirin.
7. Regex ve Index Kullanımı
- Büyük/Küçük Harf Duyarsız Arama (
i
option): Index kullanılmaz. - Büyük/Küçük Harf Duyarlı Arama: Index kullanılabilir.
Örnek:
Aşağıdaki örnekte, name
alanı üzerinde bir index oluşturuluyor ve büyük/küçük harf duyarlı regex sorgusu yapılıyor:
db.collection.createIndex({ name: 1 });
db.collection.find({ name: /^Ali/ });
Bu sorgu, name
alanı üzerindeki index’i kullanır.
8. Regex ve $text Operatörü Karşılaştırması
- Regex: Metin alanlarında belirli bir desenle eşleşen değerleri bulmak için kullanılır.
- $text: Metin alanlarında tam metin araması yapmak için kullanılır. Regex’den daha hızlıdır, ancak regex kadar esnek değildir.
Örnek:
Aşağıdaki örnekte, description
alanında “mongodb” veya “database” kelimelerini içeren belgeler aranıyor:
db.collection.find({ $text: { $search: "mongodb database" } });
Text search ve indexleme
1. Text Search Nedir?
MongoDB’de text search, metin alanları üzerinde tam metin araması yapmanıza olanak tanır. Bu özellik, belirli kelime veya kelime öbeklerini içeren belgeleri bulmak için kullanılır. Text search, regex’e kıyasla daha hızlı ve ölçeklenebilirdir.
2. Text Index Oluşturma
Text search yapabilmek için öncelikle ilgili alanlar üzerinde bir text index oluşturmanız gerekir. Text index, MongoDB’nin metin aramalarını hızlandırmak için kullandığı özel bir index türüdür.
Sözdizimi:
db.collection.createIndex({ field: "text" });
Örnek:
Aşağıdaki örnekte, title
ve description
alanları üzerinde bir text index oluşturuluyor:
db.collection.createIndex({ title: "text", description: "text" });
Not:
- Bir koleksiyonda sadece bir tane text index olabilir.
- Text index, birden fazla alan üzerinde oluşturulabilir.
3. Text Search Sorguları
Text index oluşturulduktan sonra, $text
operatörü ile metin araması yapabilirsiniz.
Sözdizimi:
db.collection.find({ $text: { $search: "aranacak kelime veya kelimeler" } });
Örnek:
Aşağıdaki örnekte, title
veya description
alanlarında “mongodb” veya “database” kelimelerini içeren belgeler aranıyor:
db.collection.find({ $text: { $search: "mongodb database" } });
Açıklama:
- Bu sorgu,
title
veyadescription
alanlarında “mongodb” veya “database” kelimelerini içeren belgeleri döndürür. - Varsayılan olarak,
$search
içindeki kelimeler OR mantığı ile birleştirilir.
4. Text Search Operatörleri
a) $search
Aranacak kelime veya kelime öbeklerini belirtir.
b) $language
Metin araması yapılırken kullanılacak dili belirtir. Örneğin, “en” (İngilizce) veya “tr” (Türkçe).
c) $caseSensitive
Büyük/küçük harf duyarlılığını belirtir. Varsayılan olarak false
‘dur.
d) $diacriticSensitive
Aksan işaretlerine duyarlılığı belirtir. Varsayılan olarak false
‘dur.
Örnek:
Aşağıdaki örnekte, title
veya description
alanlarında “mongodb” kelimesini içeren belgeler aranıyor (büyük/küçük harf duyarlı ve aksan işaretlerine duyarlı):
db.collection.find({
$text: {
$search: "mongodb",
$language: "en",
$caseSensitive: true,
$diacriticSensitive: true
}
});
5. Text Search ve Puanlama (Scoring)
MongoDB, text search sorguları sonucunda her belge için bir puan (score) hesaplar. Bu puan, belgenin sorguyla ne kadar eşleştiğini gösterir. Puanı kullanarak sonuçları sıralayabilirsiniz.
Sözdizimi:
db.collection.find(
{ $text: { $search: "aranacak kelime veya kelimeler" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } });
Örnek:
Aşağıdaki örnekte, title
veya description
alanlarında “mongodb” kelimesini içeren belgeler aranıyor ve sonuçlar puanlarına göre sıralanıyor:
db.collection.find(
{ $text: { $search: "mongodb" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } });
Açıklama:
- Bu sorgu,
title
veyadescription
alanlarında “mongodb” kelimesini içeren belgeleri bulur ve puanlarına göre sıralar.
6. Text Search ve Stop Words
MongoDB, text search sırasında stop words (örneğin, “and”, “the”, “of” gibi yaygın kelimeler) filtreler. Bu kelimeler, arama sonuçlarını etkilemez.
Örnek:
Aşağıdaki örnekte, title
veya description
alanlarında “mongodb and database” kelimelerini içeren belgeler aranıyor:
db.collection.find({ $text: { $search: "mongodb and database" } });
Açıklama:
- Bu sorgu,
title
veyadescription
alanlarında “mongodb” ve “database” kelimelerini içeren belgeleri döndürür. “and” kelimesi stop word olduğu için dikkate alınmaz.
7. Text Search ve Phrase Search
Text search, belirli bir kelime öbeği (phrase) ile eşleşen belgeleri bulmak için de kullanılabilir. Kelime öbeği, çift tırnak içinde belirtilir.
Örnek:
Aşağıdaki örnekte, title
veya description
alanlarında “mongodb database” kelime öbeğini içeren belgeler aranıyor:
db.collection.find({ $text: { $search: "\"mongodb database\"" } });
Açıklama:
- Bu sorgu,
title
veyadescription
alanlarında “mongodb database” kelime öbeğini içeren belgeleri döndürür.
8. Text Search ve Indexleme Performansı
- Text index, metin aramalarını hızlandırır, ancak disk alanı ve yazma performansı üzerinde ek yük oluşturabilir.
- Text index, büyük metin alanları üzerinde oluşturulduğunda daha fazla disk alanı kullanır.
- Text index, sadece metin alanları üzerinde çalışır. Sayısal veya diğer veri türleri için kullanılamaz.
9. Text Search ve Diğer Operatörlerle Birlikte Kullanım
Text search, diğer MongoDB operatörleriyle birlikte kullanılarak daha karmaşık sorgular oluşturulabilir.
Örnek:
Aşağıdaki örnekte, title
veya description
alanlarında “mongodb” kelimesini içeren ve age
alanı 25’ten büyük olan belgeler aranıyor:
db.collection.find({
$text: { $search: "mongodb" },
age: { $gt: 25 }
});
Aggregation Framework
Pipeline kavramı
Pipeline Kavramı
Pipeline, bir dizi aşamadan (stage) oluşur ve her aşama, veri kümesine belirli bir işlem uygular. Örneğin, verileri filtrelemek, gruplamak, sıralamak, yeni alanlar eklemek veya var olan alanları değiştirmek gibi işlemler yapılabilir. Pipeline’ın her aşaması, bir önceki aşamanın çıktısını girdi olarak alır ve sonuçları bir sonraki aşamaya aktarır.
Temel Aşamalar (Stages)
- $match: Veri kümesini belirli bir kritere göre filtreler. SQL’deki
WHERE
koşuluna benzer. - $group: Verileri belirli bir alana göre gruplar ve toplam, ortalama, maksimum, minimum gibi agregasyon işlemleri yapar.
- $sort: Verileri belirli bir alana göre sıralar.
- $project: Çıktıda hangi alanların görüneceğini belirler veya yeni alanlar ekler.
- $limit: Çıktıdaki belge sayısını sınırlar.
- $skip: Belirli sayıda belgeyi atlar.
- $unwind: Dizi tipindeki alanları ayrı belgelere ayırır.
- $lookup: İki koleksiyonu birleştirir (join işlemi).
Örnek Senaryo
Diyelim ki bir orders
koleksiyonumuz var ve bu koleksiyonda her bir siparişin customer_id
, amount
ve status
alanları bulunuyor. Amacımız, “completed” durumundaki siparişleri müşteri bazında gruplayıp, her müşterinin toplam sipariş tutarını hesaplamak ve bu tutara göre sıralamak.
Adım 1: $match ile Filtreleme
İlk olarak, sadece “completed” durumundaki siparişleri seçmek için $match
aşamasını kullanırız.
db.orders.aggregate([
{
$match: { status: "completed" }
}
])
Adım 2: $group ile Gruplama
Daha sonra, customer_id
alanına göre gruplama yapıp, her müşterinin toplam sipariş tutarını hesaplarız.
db.orders.aggregate([
{
$match: { status: "completed" }
},
{
$group: {
_id: "$customer_id",
totalAmount: { $sum: "$amount" }
}
}
])
Adım 3: $sort ile Sıralama
Son olarak, toplam sipariş tutarına göre sıralama yaparız.
db.orders.aggregate([
{
$match: { status: "completed" }
},
{
$group: {
_id: "$customer_id",
totalAmount: { $sum: "$amount" }
}
},
{
$sort: { totalAmount: -1 } // -1: Azalan sıralama, 1: Artan sıralama
}
])
Pipeline’ın Avantajları
- Esneklik: Pipeline, veri işleme süreçlerinde büyük bir esneklik sağlar. Her aşama, veri üzerinde farklı bir işlem yapabilir.
- Performans: MongoDB, pipeline’ı optimize ederek verimli bir şekilde çalıştırır. Özellikle büyük veri kümeleri üzerinde hızlı sonuçlar alınabilir.
- Karmaşık Sorgular: SQL’de yapılması zor olan karmaşık sorgular, pipeline ile kolayca gerçekleştirilebilir.
İleri Düzey Aşamalar
- $lookup: İki koleksiyonu birleştirmek için kullanılır. Örneğin,
orders
koleksiyonundaki her siparişicustomers
koleksiyonundaki müşteri bilgileriyle birleştirebiliriz.
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customer_id",
foreignField: "_id",
as: "customer_info"
}
}
])
- $unwind: Dizi tipindeki alanları ayrı belgelere ayırır. Örneğin, bir siparişin birden fazla ürün içermesi durumunda, her ürün için ayrı bir belge oluşturulabilir.
db.orders.aggregate([
{
$unwind: "$products"
}
])
Stage’ler ($match, $group, $sort, $project)
1. $match Aşaması
Açıklama:
$match
aşaması, veri kümesini belirli bir kritere göre filtrelemek için kullanılır. SQL’deki WHERE
koşuluna benzer şekilde çalışır. Bu aşama, pipeline’ın başında kullanıldığında, işlenecek belge sayısını azaltarak performansı artırır.
Kullanım Senaryosu:
- Belirli bir duruma sahip belgeleri seçmek (örneğin, “completed” durumundaki siparişler).
- Belirli bir tarih aralığındaki belgeleri filtrelemek.
- Belirli bir değere eşit olan alanları seçmek.
Sözdizimi:
{ $match: { <query> } }
Örnek:
Diyelim ki bir orders
koleksiyonumuz var ve sadece “completed” durumundaki siparişleri seçmek istiyoruz.
db.orders.aggregate([
{
$match: { status: "completed" }
}
])
Bu sorgu, status
alanı “completed” olan tüm belgeleri döndürür.
2. $group Aşaması
Açıklama:
$group
aşaması, verileri belirli bir alana göre gruplamak ve bu gruplar üzerinde agregasyon işlemleri (toplam, ortalama, maksimum, minimum vb.) yapmak için kullanılır. SQL’deki GROUP BY
ifadesine benzer.
Kullanım Senaryosu:
- Müşteri bazında toplam sipariş tutarını hesaplamak.
- Her kategorideki ürün sayısını bulmak.
- Ortalama sipariş tutarını hesaplamak.
Sözdizimi:
{
$group: {
_id: <expression>, // Gruplama yapılacak alan
<field1>: { <accumulator1>: <expression1> }, // Agregasyon işlemleri
...
}
}
Örnek:
orders
koleksiyonundaki siparişleri customer_id
alanına göre gruplayıp, her müşterinin toplam sipariş tutarını hesaplayalım.
db.orders.aggregate([
{
$group: {
_id: "$customer_id",
totalAmount: { $sum: "$amount" }
}
}
])
Bu sorgu, her müşteri için customer_id
ve totalAmount
(toplam sipariş tutarı) bilgilerini döndürür.
3. $sort Aşaması
Açıklama:
$sort
aşaması, verileri belirli bir alana göre sıralamak için kullanılır. Artan (1) veya azalan (-1) sıralama yapılabilir.
Kullanım Senaryosu:
- Siparişleri tutara göre sıralamak.
- Müşterileri toplam harcamalarına göre sıralamak.
- Tarihe göre en yeni veya en eski belgeleri sıralamak.
Sözdizimi:
{ $sort: { <field1>: <sort order>, <field2>: <sort order>, ... } }
Örnek:
orders
koleksiyonundaki siparişleri amount
alanına göre azalan şekilde sıralayalım.
db.orders.aggregate([
{
$sort: { amount: -1 } // -1: Azalan, 1: Artan
}
])
Bu sorgu, siparişleri en yüksek tutardan en düşük tutara doğru sıralar.
4. $project Aşaması
Açıklama:
$project
aşaması, çıktıdaki belgelerde hangi alanların görüneceğini belirlemek veya yeni alanlar eklemek için kullanılır. SQL’deki SELECT
ifadesine benzer. Ayrıca, var olan alanları yeniden adlandırabilir veya hesaplanmış alanlar ekleyebilirsiniz.
Kullanım Senaryosu:
- Sadece belirli alanları seçmek (örneğin,
customer_id
veamount
). - Yeni hesaplanmış alanlar eklemek (örneğin, vergi tutarı).
- Alanları yeniden adlandırmak.
Sözdizimi:
{
$project: {
<field1>: <expression>, // Görüntülenecek veya hesaplanacak alan
<field2>: 1, // 1: Alanı dahil et, 0: Alanı hariç tut
...
}
}
Örnek:
orders
koleksiyonundaki belgelerde sadece customer_id
ve amount
alanlarını seçelim ve amount
alanını total
olarak yeniden adlandıralım.
db.orders.aggregate([
{
$project: {
customer_id: 1,
total: "$amount",
_id: 0 // _id alanını hariç tut
}
}
])
Bu sorgu, çıktıda sadece customer_id
ve total
alanlarını gösterir.
Tüm Aşamaları Birleştiren Örnek
Şimdi, yukarıdaki tüm aşamaları birleştiren bir örnek yapalım. Senaryomuz şu şekilde olsun:
- Sadece “completed” durumundaki siparişleri seçelim (
$match
). - Bu siparişleri
customer_id
alanına göre gruplayıp, her müşterinin toplam sipariş tutarını hesaplayalım ($group
). - Toplam sipariş tutarına göre azalan şekilde sıralayalım (
$sort
). - Sonuçlarda sadece
customer_id
vetotalAmount
alanlarını gösterelim ($project
).
db.orders.aggregate([
{
$match: { status: "completed" }
},
{
$group: {
_id: "$customer_id",
totalAmount: { $sum: "$amount" }
}
},
{
$sort: { totalAmount: -1 }
},
{
$project: {
customer_id: "$_id",
totalAmount: 1,
_id: 0
}
}
])
Çıktı:
[
{ "customer_id": "12345", "totalAmount": 1500 },
{ "customer_id": "67890", "totalAmount": 1200 },
...
]
$lookup ile ilişkisel sorgular
$lookup Aşaması Nedir?
$lookup
, iki koleksiyonu birleştirmek için kullanılan bir aggregation aşamasıdır. Bu aşama, bir koleksiyondaki belgeleri, başka bir koleksiyondaki eşleşen belgelerle birleştirir. Örneğin, orders
koleksiyonundaki her siparişi, customers
koleksiyonundaki müşteri bilgileriyle birleştirebilirsiniz.
Temel Kullanım Senaryoları:
- Siparişlerle müşteri bilgilerini birleştirmek.
- Ürünlerle kategorileri birleştirmek.
- Yorumlarla kullanıcı bilgilerini birleştirmek.
$lookup Sözdizimi
$lookup
aşamasının temel sözdizimi aşağıdaki gibidir:
{
$lookup: {
from: <koleksiyon_adı>, // Birleştirilecek koleksiyon
localField: <alan_adı>, // Mevcut koleksiyondaki eşleşecek alan
foreignField: <alan_adı>, // Birleştirilecek koleksiyondaki eşleşecek alan
as: <çıktı_alani> // Birleştirilen belgelerin ekleneceği alan
}
}
Parametreler:
- from: Birleştirilecek koleksiyonun adı.
- localField: Mevcut koleksiyondaki eşleşecek alan.
- foreignField: Birleştirilecek koleksiyondaki eşleşecek alan.
- as: Birleştirilen belgelerin ekleneceği alan. Bu alan, bir dizi olarak eklenir.
$lookup Örnekleri
Senaryo 1: Siparişler ve Müşteriler
Diyelim ki iki koleksiyonumuz var:
- orders: Sipariş bilgilerini içerir (
customer_id
,amount
,status
). - customers: Müşteri bilgilerini içerir (
_id
,name
,email
).
Amacımız, her siparişi ilgili müşteri bilgileriyle birleştirmek.
orders Koleksiyonu:
[
{ "_id": 1, "customer_id": 101, "amount": 100, "status": "completed" },
{ "_id": 2, "customer_id": 102, "amount": 200, "status": "pending" }
]
customers Koleksiyonu:
[
{ "_id": 101, "name": "Ahmet Yılmaz", "email": "ahmet@example.com" },
{ "_id": 102, "name": "Mehmet Demir", "email": "mehmet@example.com" }
]
Sorgu:
db.orders.aggregate([
{
$lookup: {
from: "customers", // Birleştirilecek koleksiyon
localField: "customer_id", // orders koleksiyonundaki alan
foreignField: "_id", // customers koleksiyonundaki alan
as: "customer_info" // Birleştirilen bilgilerin ekleneceği alan
}
}
])
Çıktı:
[
{
"_id": 1,
"customer_id": 101,
"amount": 100,
"status": "completed",
"customer_info": [
{
"_id": 101,
"name": "Ahmet Yılmaz",
"email": "ahmet@example.com"
}
]
},
{
"_id": 2,
"customer_id": 102,
"amount": 200,
"status": "pending",
"customer_info": [
{
"_id": 102,
"name": "Mehmet Demir",
"email": "mehmet@example.com"
}
]
}
]
Bu sorgu, her siparişi ilgili müşteri bilgileriyle birleştirir ve customer_info
alanı altında müşteri bilgilerini ekler.
Senaryo 2: Dizi Alanlarıyla $lookup Kullanımı
Bazen bir belgedeki alan bir dizi olabilir. Örneğin, bir siparişte birden fazla ürün olabilir. Bu durumda, $lookup
ile dizi içindeki her bir öğeyi başka bir koleksiyonla eşleştirebilirsiniz.
orders Koleksiyonu:
[
{ "_id": 1, "product_ids": [201, 202], "status": "completed" },
{ "_id": 2, "product_ids": [203], "status": "pending" }
]
products Koleksiyonu:
[
{ "_id": 201, "name": "Laptop", "price": 1500 },
{ "_id": 202, "name": "Mouse", "price": 50 },
{ "_id": 203, "name": "Keyboard", "price": 100 }
]
Sorgu:
db.orders.aggregate([
{
$lookup: {
from: "products",
localField: "product_ids",
foreignField: "_id",
as: "product_details"
}
}
])
Çıktı:
[
{
"_id": 1,
"product_ids": [201, 202],
"status": "completed",
"product_details": [
{ "_id": 201, "name": "Laptop", "price": 1500 },
{ "_id": 202, "name": "Mouse", "price": 50 }
]
},
{
"_id": 2,
"product_ids": [203],
"status": "pending",
"product_details": [
{ "_id": 203, "name": "Keyboard", "price": 100 }
]
}
]
Bu sorgu, her siparişteki ürün ID’lerini products
koleksiyonuyla eşleştirir ve ürün detaylarını product_details
alanı altında ekler.
$lookup ile İlişkisel Sorguların Avantajları
- Esneklik: İlişkisel veri modelleriyle çalışırken büyük bir esneklik sağlar.
- Performans: Büyük veri kümeleri üzerinde optimize edilmiş bir şekilde çalışır.
- Karmaşık Sorgular: SQL’deki
JOIN
işlemlerine benzer şekilde karmaşık sorgular yapılabilir.
$lookup ile İlişkisel Sorguların Sınırlamaları
- Tek Yönlü Birleştirme:
$lookup
, sadece iki koleksiyon arasında tek yönlü birleştirme yapar. Çoklu birleştirmeler için birden fazla$lookup
aşaması kullanılabilir. - Performans: Çok büyük veri kümelerinde
$lookup
işlemi performans sorunlarına neden olabilir. Bu durumda, veri modelinizi gözden geçirmek faydalı olabilir.
$unwind kullanımı
$unwind
, bir dizi alanını alır ve bu dizi içindeki her bir öğe için yeni bir belge oluşturur. Örneğin, bir belgede tags
adında bir dizi alanı varsa ve bu dizi ["mongodb", "aggregation", "unwind"]
şeklinde ise, $unwind
kullanıldığında bu belge, her bir dizi öğesi için ayrı bir belgeye dönüşür:
{ tags: "mongodb" }
{ tags: "aggregation" }
{ tags: "unwind" }
$unwind
Kullanım Senaryoları
- Dizi İçindeki Öğeleri Ayrı Ayrı İşlemek: Örneğin, bir blog yazısının etiketlerini (
tags
) ayrı ayrı işlemek istiyorsanız,$unwind
kullanarak her bir etiket için ayrı bir belge oluşturabilirsiniz. - Gruplama ve Toplama İşlemleri:
$unwind
kullanarak dizi öğelerini ayrı belgelere dönüştürdükten sonra,$group
gibi operatörlerle gruplama veya toplama işlemleri yapabilirsiniz. - Dizi İçindeki Öğeleri Filtreleme:
$unwind
ile dizi öğelerini ayrı belgelere dönüştürdükten sonra,$match
gibi operatörlerle filtreleme yapabilirsiniz.
$unwind
Sözdizimi
{ $unwind: <field path> }
<field path>
: Açılacak (unwind) dizi alanının yolunu belirtir.
$unwind
Örnekleri
Örnek 1: Basit $unwind
Kullanımı
Aşağıdaki gibi bir orders
koleksiyonumuz olduğunu varsayalım:
[
{ _id: 1, order_id: "123", items: ["apple", "banana", "cherry"] },
{ _id: 2, order_id: "456", items: ["orange", "grape"] }
]
$unwind
kullanarak items
dizisini açalım:
db.orders.aggregate([
{ $unwind: "$items" }
])
Bu sorgu, aşağıdaki çıktıyı üretecektir:
[
{ _id: 1, order_id: "123", items: "apple" },
{ _id: 1, order_id: "123", items: "banana" },
{ _id: 1, order_id: "123", items: "cherry" },
{ _id: 2, order_id: "456", items: "orange" },
{ _id: 2, order_id: "456", items: "grape" }
]
Örnek 2: $unwind
ile $group
Kullanımı
$unwind
ile dizi öğelerini ayrı belgelere dönüştürdükten sonra, $group
ile gruplama yapabiliriz. Örneğin, her bir ürünün kaç kez sipariş edildiğini bulalım:
db.orders.aggregate([
{ $unwind: "$items" },
{ $group: { _id: "$items", total: { $sum: 1 } } }
])
Bu sorgu, aşağıdaki çıktıyı üretecektir:
[
{ _id: "apple", total: 1 },
{ _id: "banana", total: 1 },
{ _id: "cherry", total: 1 },
{ _id: "orange", total: 1 },
{ _id: "grape", total: 1 }
]
Örnek 3: $unwind
ile $match
Kullanımı
$unwind
ile dizi öğelerini ayrı belgelere dönüştürdükten sonra, $match
ile filtreleme yapabiliriz. Örneğin, sadece “apple” ürününü içeren siparişleri bulalım:
db.orders.aggregate([
{ $unwind: "$items" },
{ $match: { items: "apple" } }
])
Bu sorgu, aşağıdaki çıktıyı üretecektir:
[
{ _id: 1, order_id: "123", items: "apple" }
]
$unwind
ve preserveNullAndEmptyArrays
Seçeneği
Varsayılan olarak, $unwind
operatörü, dizi alanı null
, boş dizi ([]
) veya mevcut değilse, belgeyi çıktıdan çıkarır. Ancak, bu davranışı değiştirmek için preserveNullAndEmptyArrays
seçeneğini true
olarak ayarlayabilirsiniz. Bu seçenek, null
veya boş dizi durumunda belgenin çıktıda kalmasını sağlar.
db.orders.aggregate([
{ $unwind: { path: "$items", preserveNullAndEmptyArrays: true } }
])
Bu durumda, items
alanı null
veya boş dizi olan belgeler de çıktıda yer alacaktır.
İstatistiksel operasyonlar
MongoDB Aggregation Framework, veriler üzerinde istatistiksel işlemler yapmak için aşağıdaki gibi operatörler sunar:
$group
: Verileri belirli bir alana göre gruplamak ve bu gruplar üzerinde toplama, ortalama, sayma gibi işlemler yapmak için kullanılır.$sum
: Gruplanmış veriler üzerinde toplam hesaplamak için kullanılır.$avg
: Gruplanmış veriler üzerinde ortalama hesaplamak için kullanılır.$min
: Gruplanmış veriler üzerinde minimum değeri bulmak için kullanılır.$max
: Gruplanmış veriler üzerinde maksimum değeri bulmak için kullanılır.$stdDevPop
: Gruplanmış veriler üzerinde popülasyon standart sapması hesaplamak için kullanılır.$stdDevSamp
: Gruplanmış veriler üzerinde örneklem standart sapması hesaplamak için kullanılır.$push
: Gruplanmış veriler içinde belirli bir alanın değerlerini bir dizi olarak toplamak için kullanılır.$addToSet
: Gruplanmış veriler içinde belirli bir alanın benzersiz değerlerini bir dizi olarak toplamak için kullanılır.
İstatistiksel Operasyonların Kullanım Senaryoları
- Toplam Gelir Hesaplama: Bir e-ticaret uygulamasında, her bir kategorinin toplam gelirini hesaplamak.
- Ortalama Değer Hesaplama: Bir öğrenci not sisteminde, her bir dersin ortalama notunu hesaplamak.
- Standart Sapma Hesaplama: Bir üretim sürecinde, ürün boyutlarının standart sapmasını hesaplamak.
- Minimum ve Maksimum Değer Bulma: Bir hava durumu veri setinde, her ayın minimum ve maksimum sıcaklıklarını bulmak.
İstatistiksel Operasyonların Sözdizimi ve Örnekleri
Örnek 1: Toplam Gelir Hesaplama
Aşağıdaki gibi bir sales
koleksiyonumuz olduğunu varsayalım:
[
{ _id: 1, product: "A", category: "Electronics", price: 100, quantity: 2 },
{ _id: 2, product: "B", category: "Electronics", price: 200, quantity: 1 },
{ _id: 3, product: "C", category: "Clothing", price: 50, quantity: 3 },
{ _id: 4, product: "D", category: "Clothing", price: 75, quantity: 2 }
]
Her bir kategorinin toplam gelirini hesaplamak için $group
ve $sum
kullanabiliriz:
db.sales.aggregate([
{
$group: {
_id: "$category",
totalRevenue: { $sum: { $multiply: ["$price", "$quantity"] } }
}
}
])
Bu sorgu, aşağıdaki çıktıyı üretecektir:
[
{ _id: "Electronics", totalRevenue: 400 }, // (100*2 + 200*1)
{ _id: "Clothing", totalRevenue: 250 } // (50*3 + 75*2)
]
Örnek 2: Ortalama Değer Hesaplama
Aşağıdaki gibi bir grades
koleksiyonumuz olduğunu varsayalım:
[
{ _id: 1, student: "Alice", subject: "Math", grade: 85 },
{ _id: 2, student: "Bob", subject: "Math", grade: 90 },
{ _id: 3, student: "Alice", subject: "Science", grade: 78 },
{ _id: 4, student: "Bob", subject: "Science", grade: 88 }
]
Her bir dersin ortalama notunu hesaplamak için $group
ve $avg
kullanabiliriz:
db.grades.aggregate([
{
$group: {
_id: "$subject",
averageGrade: { $avg: "$grade" }
}
}
])
Bu sorgu, aşağıdaki çıktıyı üretecektir:
[
{ _id: "Math", averageGrade: 87.5 }, // (85 + 90) / 2
{ _id: "Science", averageGrade: 83 } // (78 + 88) / 2
]
Örnek 3: Standart Sapma Hesaplama
Aşağıdaki gibi bir measurements
koleksiyonumuz olduğunu varsayalım:
[
{ _id: 1, sensor: "A", value: 10 },
{ _id: 2, sensor: "A", value: 12 },
{ _id: 3, sensor: "A", value: 11 },
{ _id: 4, sensor: "B", value: 20 },
{ _id: 5, sensor: "B", value: 22 }
]
Her bir sensörün ölçümlerinin standart sapmasını hesaplamak için $group
ve $stdDevPop
kullanabiliriz:
db.measurements.aggregate([
{
$group: {
_id: "$sensor",
stdDev: { $stdDevPop: "$value" }
}
}
])
Bu sorgu, aşağıdaki çıktıyı üretecektir:
[
{ _id: "A", stdDev: 0.816496580927726 }, // Popülasyon standart sapması
{ _id: "B", stdDev: 1.0 } // Popülasyon standart sapması
]
Örnek 4: Minimum ve Maksimum Değer Bulma
Aşağıdaki gibi bir weather
koleksiyonumuz olduğunu varsayalım:
[
{ _id: 1, month: "January", temperature: 5 },
{ _id: 2, month: "January", temperature: 7 },
{ _id: 3, month: "February", temperature: 10 },
{ _id: 4, month: "February", temperature: 12 }
]
Her bir ayın minimum ve maksimum sıcaklıklarını bulmak için $group
, $min
ve $max
kullanabiliriz:
db.weather.aggregate([
{
$group: {
_id: "$month",
minTemperature: { $min: "$temperature" },
maxTemperature: { $max: "$temperature" }
}
}
])
Bu sorgu, aşağıdaki çıktıyı üretecektir:
[
{ _id: "January", minTemperature: 5, maxTemperature: 7 },
{ _id: "February", minTemperature: 10, maxTemperature: 12 }
]
İndexleme ve Performans
Single field indexler
Single Field Index, MongoDB’de en temel ve yaygın kullanılan index türüdür. Adından da anlaşılacağı gibi, koleksiyondaki tek bir alan üzerinde oluşturulan indexlerdir. Bu indexler, belirli bir alan üzerinde yapılan sorguların performansını önemli ölçüde artırır.
Temel Özellikleri
- Sıralama Desteği: Single field indexler, hem artan (ascending) hem de azalan (descending) sıralama desteği sunar.
- Benzersiz (Unique) Index Desteği: Bir alanın benzersiz değerler içermesini zorunlu kılabilirsiniz.
- Sparse Index Desteği: Sadece indexlenen alana sahip dökümanları içeren indexler oluşturabilirsiniz.
Index Oluşturma Sözdizimi
db.collection.createIndex({ field: 1 }) // Artan sıralama için
db.collection.createIndex({ field: -1 }) // Azalan sıralama için
Örnek olarak, bir users
koleksiyonunda email
alanı için unique bir index oluşturalım:
db.users.createIndex({ email: 1 }, { unique: true })
Kullanım Senaryoları ve Örnekler
- Basit Sorgu Optimizasyonu
// Örnek koleksiyon
db.products.insertMany([
{ name: "Laptop", price: 1200, category: "Electronics" },
{ name: "Phone", price: 800, category: "Electronics" },
{ name: "Desk", price: 300, category: "Furniture" }
])
// Price alanı için index oluşturma
db.products.createIndex({ price: 1 })
// Bu sorgu artık index kullanarak daha hızlı çalışacak
db.products.find({ price: { $gt: 500 } })
- Benzersiz Değer Zorunluluğu
// Email alanı için unique index
db.users.createIndex({ email: 1 }, { unique: true })
// Aynı email ile iki kayıt oluşturmaya çalışırsak hata alırız
db.users.insertMany([
{ name: "John", email: "john@example.com" },
{ name: "Jane", email: "john@example.com" } // Bu işlem hata verecek
])
Performans Etkileri
Okuma Performansı:
- İndexlenmiş alan üzerinde yapılan sorgular çok daha hızlı çalışır
- MongoDB, index taraması yaparak ilgili dökümanları bulur
- Collection scan yerine index scan yapılır
Yazma Performansı:
- Her yazma işleminde index güncellenmesi gerekir
- Bu nedenle yazma işlemleri biraz yavaşlayabilir
- Çok fazla index kullanmak yazma performansını olumsuz etkileyebilir
Best Practices
Doğru Alan Seçimi:
- Sık sorgulanan alanlar için index oluşturun
- Nadiren sorgulanan alanlar için index oluşturmaktan kaçının
Index Boyutu:
- Index’ler RAM’de tutulur
- Çok büyük index’ler performansı olumsuz etkileyebilir
- Index boyutunu düzenli olarak monitör edin
Background İndexleme:
- Prodüksiyon ortamında index oluştururken background seçeneğini kullanın:
db.collection.createIndex({ field: 1 }, { background: true })
- Index Kullanımını İzleme:
// Sorgu planını inceleme
db.collection.find({ field: value }).explain()
Sınırlamalar ve Dikkat Edilmesi Gerekenler
32-bit Sistemler:
- Index boyutu 2GB’ı geçemez
- 64-bit sistemlerde bu sınırlama yoktur
Index Oluşturma Süresi:
- Büyük koleksiyonlarda index oluşturma işlemi zaman alabilir
- Bu süreçte sistem kaynaklarının kullanımı artar
Unique Index Kısıtlamaları:
- Var olan verilerde duplicate değerler varsa unique index oluşturulamaz
- Null değerler için özel dikkat gerekir
Sonuç
Single field indexler, MongoDB’de performans optimizasyonunun temel taşıdır. Doğru kullanıldığında sorgu performansını önemli ölçüde artırırken, yanlış kullanımı sistem performansını olumsuz etkileyebilir. Bu nedenle, index stratejinizi uygulama ihtiyaçlarınıza göre dikkatli bir şekilde planlamalısınız.
Compound indexler
Compound Index, MongoDB’de birden fazla alanın birlikte indexlenmesini sağlayan index türüdür. Bu indexler, birden fazla alan üzerinde yapılan sorguların performansını optimize etmek için kullanılır.
Temel Özellikleri
- Çoklu Alan Desteği: Birden fazla alanı tek bir index yapısında birleştirir.
- Sıralama Esnekliği: Her alan için ayrı ayrı artan veya azalan sıralama belirlenebilir.
- Index Prefix Kullanımı: Index’in sol tarafındaki alanlar bağımsız olarak kullanılabilir.
- Maximum Alan Sayısı: Bir compound index en fazla 32 alan içerebilir.
Index Oluşturma Sözdizimi
// Temel syntax
db.collection.createIndex({ field1: 1, field2: -1, field3: 1 })
// Örnek: users koleksiyonu için compound index
db.users.createIndex({
age: 1, // Artan sıralama
city: 1, // Artan sıralama
lastName: -1 // Azalan sıralama
})
Kullanım Senaryoları ve Örnekler
- E-ticaret Ürün Kataloğu
// Örnek koleksiyon oluşturma
db.products.insertMany([
{ category: "Electronics", brand: "Apple", price: 1200 },
{ category: "Electronics", brand: "Samsung", price: 1000 },
{ category: "Clothing", brand: "Nike", price: 100 }
])
// Compound index oluşturma
db.products.createIndex({ category: 1, brand: 1, price: -1 })
// Bu sorgular index'i kullanabilir
db.products.find({ category: "Electronics" })
db.products.find({ category: "Electronics", brand: "Apple" })
db.products.find({ category: "Electronics", brand: "Apple", price: { $gt: 1000 } })
- Kullanıcı Verilerinde Arama
// Users koleksiyonu için compound index
db.users.createIndex({
country: 1,
city: 1,
age: -1
})
// Örnek sorgular
db.users.find({ country: "Turkey", city: "Istanbul" })
db.users.find({ country: "Turkey" }).sort({ age: -1 })
Performans Özellikleri ve ESR (Equality, Sort, Range) Kuralı
ESR Kuralı, compound index tasarımında önemli bir prensiptir:
- E (Equality): Tam eşitlik koşulları
- S (Sort): Sıralama koşulları
- R (Range): Aralık sorguları
// Örnek senaryo
db.orders.createIndex({
status: 1, // Equality için
orderDate: -1, // Sort için
amount: 1 // Range için
})
// Optimal sorgu örneği
db.orders.find({
status: "pending", // Equality
amount: { $gt: 100, $lt: 1000 } // Range
}).sort({ orderDate: -1 }) // Sort
Index Intersection vs Compound Index
- Index Intersection (İndex Kesişimi)
// İki ayrı index
db.collection.createIndex({ field1: 1 })
db.collection.createIndex({ field2: 1 })
// MongoDB bu sorgu için iki index'i kesiştirebilir
db.collection.find({ field1: "value1", field2: "value2" })
- Compound Index
// Tek bir compound index
db.collection.createIndex({ field1: 1, field2: 1 })
// Bu sorgu için tek index kullanılır
db.collection.find({ field1: "value1", field2: "value2" })
Best Practices
- Sıralama Optimizasyonu:
// Doğru index tasarımı
db.collection.createIndex({
department: 1, // Filtreleme için
salary: -1 // Sıralama için
})
// Etkin sorgu
db.collection.find({ department: "IT" }).sort({ salary: -1 })
- Cardinality’ye Göre Alan Sıralaması:
- Yüksek cardinality (benzersiz değer sayısı) olan alanları index’in başına koyun
// Daha etkili
db.users.createIndex({ email: 1, status: 1 }) // email daha unique
// Daha az etkili
db.users.createIndex({ status: 1, email: 1 }) // status daha az unique
Sınırlamalar ve Dikkat Edilmesi Gerekenler
Index Boyutu:
- Her ek alan, index boyutunu artırır
- RAM kullanımını düzenli kontrol edin
Yazma Performansı:
- Çok fazla compound index, yazma performansını düşürebilir
- Sadece gerekli indexleri oluşturun
Index Kullanımını İzleme:
// Sorgu planı analizi
db.collection.find({...}).explain("executionStats")
Örnek Senaryo: Blog Uygulaması
// Posts koleksiyonu için compound index
db.posts.createIndex({
authorId: 1, // Yazar bazlı filtreleme
category: 1, // Kategori filtreleme
publishDate: -1 // Tarih sıralama
})
// Kullanım örnekleri
// 1. Belirli bir yazarın son postları
db.posts.find({ authorId: "123" }).sort({ publishDate: -1 })
// 2. Belirli bir kategorideki son postlar
db.posts.find({ category: "Technology" }).sort({ publishDate: -1 })
// 3. Belirli bir yazarın belirli kategorideki son postları
db.posts.find({
authorId: "123",
category: "Technology"
}).sort({ publishDate: -1 })
Sonuç
Compound indexler, karmaşık sorgu senaryolarında performansı önemli ölçüde artırabilir. Ancak, her index’in bir maliyeti olduğunu unutmamak gerekir. Index tasarımı yaparken:
- Uygulama sorgu paternlerini analiz edin
- ESR kuralını göz önünde bulundurun
- Index boyutunu ve yazma performansını dengeleyin
- Düzenli olarak index kullanımını monitör edin
Bu prensipleri uygulayarak, MongoDB’de etkili bir compound index stratejisi geliştirebilirsiniz.
Text indexler
Text index’ler, MongoDB’de metin bazlı aramaları etkin bir şekilde gerçekleştirmek için kullanılan özel bir index türüdür. Bu index’ler, dökümanlar içindeki metin içeriğinde arama yapılmasını sağlar ve dil desteği gibi gelişmiş özellikler sunar.
Temel Özellikleri
- Koleksiyon Başına Tek Text Index: Bir koleksiyonda sadece bir text index oluşturulabilir
- Çoklu Alan Desteği: Birden fazla metin alanı tek bir text index’te birleştirilebilir
- Dil Desteği: Farklı dillerde arama yapabilme ve dil spesifik tokenization
- Ağırlıklandırma: Farklı alanlara farklı önem dereceleri atanabilir
Text Index Oluşturma
// Temel syntax
db.collection.createIndex({ field: "text" })
// Birden fazla alan için text index
db.collection.createIndex({
title: "text",
description: "text",
content: "text"
})
// Ağırlıklandırma ile text index
db.collection.createIndex(
{
title: "text",
description: "text",
content: "text"
},
{
weights: {
title: 10,
description: 5,
content: 1
}
}
)
Kullanım Örnekleri
- Blog Post Araması
// Örnek koleksiyon oluşturma
db.posts.insertMany([
{
title: "MongoDB Text Search",
content: "Learn how to use text search in MongoDB",
tags: ["mongodb", "database", "search"]
},
{
title: "Advanced MongoDB Features",
content: "Discover advanced features in MongoDB",
tags: ["mongodb", "advanced"]
}
])
// Text index oluşturma
db.posts.createIndex({ title: "text", content: "text" })
// Metin araması yapma
db.posts.find({ $text: { $search: "mongodb search" } })
// Skor ile sıralama
db.posts.find(
{ $text: { $search: "mongodb search" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })
- Dil Desteği ile Arama
// Türkçe dil desteği ile index oluşturma
db.articles.createIndex(
{ content: "text" },
{ default_language: "turkish" }
)
// Belirli bir dilde arama yapma
db.articles.find({
$text: {
$search: "bilgisayar",
$language: "turkish"
}
})
Gelişmiş Arama Özellikleri
- Phrase Araması
// Tam eşleşme için tırnak kullanımı
db.posts.find({
$text: { $search: "\"exact phrase\"" }
})
- Negatif Arama (Hariç Tutma)
// "mongodb" içeren ama "sql" içermeyen dökümanlar
db.posts.find({
$text: { $search: "mongodb -sql" }
})
Performans Optimizasyonu
- Index Boyutu Yönetimi
// Sadece gerekli alanları indexleme
db.collection.createIndex(
{ title: "text" },
{ sparse: true }
)
- Wildcard Text Index
// Tüm string alanlar için text index
db.collection.createIndex({ "$**": "text" })
Best Practices
Alan Seçimi:
- Arama yapılacak alanları dikkatli seçin
- Gereksiz alanları text index’e dahil etmeyin
Ağırlıklandırma Stratejisi:
// Önem derecesine göre ağırlıklandırma
db.products.createIndex(
{
name: "text",
description: "text",
category: "text"
},
{
weights: {
name: 10,
description: 5,
category: 2
}
}
)
Dil Optimizasyonu:
// Çok dilli içerik için
db.content.insert({
title: "MongoDB Guide",
content: "MongoDB kullanım kılavuzu",
language: "tr"
})
db.content.find({
$text: {
$search: "kılavuz",
$language: "tr"
}
})
Pratik Örnek: E-ticaret Ürün Araması
// Ürün koleksiyonu oluşturma
db.products.insertMany([
{
name: "Gaming Laptop",
description: "High performance gaming laptop with RTX 3080",
category: "Electronics",
tags: ["gaming", "laptop", "computer"]
},
{
name: "Professional Camera",
description: "DSLR camera for professional photography",
category: "Photography",
tags: ["camera", "professional", "photo"]
}
])
// Text index oluşturma
db.products.createIndex({
name: "text",
description: "text",
tags: "text"
}, {
weights: {
name: 10,
description: 5,
tags: 3
}
})
// Arama örnekleri
// 1. Basit arama
db.products.find({
$text: { $search: "gaming laptop" }
})
// 2. Skor ile sıralama
db.products.find(
{ $text: { $search: "professional" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })
// 3. Kategori ve metin aramasını birleştirme
db.products.find({
category: "Electronics",
$text: { $search: "gaming" }
})
Sınırlamalar ve Dikkat Edilmesi Gerekenler
Koleksiyon Başına Tek Text Index:
- Birden fazla text index oluşturamazsınız
- Mevcut text index’i değiştirmek için önce silmeniz gerekir
Performans İmplikasyonları:
- Text index’ler büyük bellek kullanabilir
- Yazma işlemlerini yavaşlatabilir
- Düzenli performans izlemesi yapın
Dil Desteği Sınırlamaları:
- Her döküman için tek bir dil belirtilebilir
- Bazı diller için sınırlı destek olabilir
Sonuç
Text index’ler, MongoDB’de güçlü metin arama özellikleri sunar. Ancak:
- Doğru alan seçimi
- Uygun ağırlıklandırma
- Performans optimizasyonu
- Dil desteği
gibi faktörleri dikkate alarak kullanılmalıdır. Text index’lerin sınırlamalarını ve maliyetlerini göz önünde bulundurarak, uygulamanızın ihtiyaçlarına göre en uygun text arama stratejisini belirlemelisiniz.
Geospatial indexler
Geospatial Index Nedir?
Geospatial indexler, MongoDB’de coğrafi konum bazlı sorguları optimize etmek için kullanılan özel index türüdür. Bu indexler, konum tabanlı uygulamalarda yakındaki yerleri bulma, belirli bir alan içindeki noktaları sorgulama gibi işlemleri hızlandırır.
Geospatial Index Türleri
2dsphere Index:
- Dünya benzeri küresel geometri için kullanılır
- GeoJSON formatını destekler
- Gerçek dünya uygulamaları için idealdir
2d Index:
- Düzlemsel geometri için kullanılır
- X ve Y koordinatları ile çalışır
- Oyun gibi düzlemsel uygulamalar için uygundur
2dsphere Index Oluşturma ve Kullanım
// 2dsphere index oluşturma
db.places.createIndex({ location: "2dsphere" })
// Örnek veri ekleme (GeoJSON Point)
db.places.insertMany([
{
name: "Cafe A",
location: {
type: "Point",
coordinates: [28.979530, 41.015137] // [Longitude, Latitude]
}
},
{
name: "Restaurant B",
location: {
type: "Point",
coordinates: [28.977385, 41.016793]
}
}
])
GeoJSON Desteklenen Geometri Tipleri
- Point: Tek bir konum noktası
{
type: "Point",
coordinates: [longitude, latitude]
}
- LineString: Çizgi/Rota
{
type: "LineString",
coordinates: [[lon1, lat1], [lon2, lat2], [lon3, lat3]]
}
- Polygon: Kapalı alan
{
type: "Polygon",
coordinates: [
[[lon1, lat1], [lon2, lat2], [lon3, lat3], [lon1, lat1]]
]
}
Geospatial Sorgular
- $near: En yakın konumları bulma
// Belirli bir noktaya yakın yerleri bulma
db.places.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [28.979530, 41.015137]
},
$maxDistance: 1000, // metre cinsinden
$minDistance: 100 // metre cinsinden
}
}
})
- $geoWithin: Alan içindeki konumları bulma
// Dikdörtgen alan içindeki yerler
db.places.find({
location: {
$geoWithin: {
$box: [
[28.97, 41.01], // Sol alt köşe
[28.99, 41.02] // Sağ üst köşe
]
}
}
})
// Daire içindeki yerler
db.places.find({
location: {
$geoWithin: {
$centerSphere: [
[28.979530, 41.015137], // Merkez nokta
1 / 6371 // Yarıçap (km cinsinden)
]
}
}
})
- $geoIntersects: Kesişen geometrileri bulma
// Belirli bir rota ile kesişen yerler
db.places.find({
location: {
$geoIntersects: {
$geometry: {
type: "LineString",
coordinates: [
[28.97, 41.01],
[28.99, 41.02]
]
}
}
}
})
Pratik Örnek: Yakındaki Restoranlar Uygulaması
// Restoran koleksiyonu oluşturma
db.restaurants.insertMany([
{
name: "Pizza Place",
cuisine: "Italian",
location: {
type: "Point",
coordinates: [28.979530, 41.015137]
},
rating: 4.5
},
{
name: "Sushi Bar",
cuisine: "Japanese",
location: {
type: "Point",
coordinates: [28.977385, 41.016793]
},
rating: 4.8
}
])
// 2dsphere index oluşturma
db.restaurants.createIndex({ location: "2dsphere" })
// Compound index (konum + rating)
db.restaurants.createIndex({
location: "2dsphere",
rating: 1
})
// Kullanıcı konumuna yakın ve yüksek puanlı restoranları bulma
db.restaurants.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [28.978500, 41.015900]
},
$maxDistance: 2000
}
},
rating: { $gte: 4.0 }
}).sort({ rating: -1 })
Performans Optimizasyonu
- Bileşik Sorgular için Compound Index:
// Konum + kategori için compound index
db.venues.createIndex({
location: "2dsphere",
category: 1
})
- Sorgu Planlayıcısı Kullanımı:
// Sorgu performansını analiz etme
db.venues.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [28.979530, 41.015137]
}
}
}
}).explain("executionStats")
Best Practices
Veri Doğrulama:
// GeoJSON validasyonu
const isValidGeoJSON = (coordinates) => {
return coordinates &&
Array.isArray(coordinates) &&
coordinates.length === 2 &&
coordinates[0] >= -180 && coordinates[0] <= 180 &&
coordinates[1] >= -90 && coordinates[1] <= 90;
}
Index Stratejisi:
- Sık kullanılan sorgular için compound index kullanın
- Gereksiz indexlerden kaçının
- Düzenli performans kontrolü yapın
Mesafe Hesaplamaları:
// Küresel mesafe hesaplama ($geoNear aggregation)
db.places.aggregate([
{
$geoNear: {
near: {
type: "Point",
coordinates: [28.979530, 41.015137]
},
distanceField: "distance",
spherical: true,
maxDistance: 5000
}
}
])
Sınırlamalar ve Dikkat Edilmesi Gerekenler
Koordinat Sıralaması:
- GeoJSON’da koordinatlar [longitude, latitude] sırasında olmalıdır
- Bu sıralama Google Maps gibi sistemlerden farklıdır
Performans İmplikasyonları:
- Büyük veri setlerinde index boyutu önemlidir
- Karmaşık polygon sorguları yavaş olabilir
Hassasiyet:
- Küresel hesaplamalarda küçük hatalar olabilir
- Çok hassas mesafe hesapları için ek kontroller gerekebilir
Sonuç
Geospatial indexler, konum tabanlı uygulamalar için güçlü bir araçtır. Doğru kullanıldığında:
- Yakındaki yerleri bulma
- Alan içi sorgulama
- Rota kesişimi
- Mesafe hesaplama
gibi işlemleri verimli bir şekilde gerçekleştirebilirsiniz. Ancak, koordinat sistemlerini doğru anlamak, uygun index stratejisi belirlemek ve performans optimizasyonu yapmak önemlidir.
Index stratejileri ve best practices
1. Index Tasarım Prensipleri
ESR (Equality, Sort, Range) Kuralı
// İyi Tasarım
db.orders.createIndex({
status: 1, // Equality (exact match)
orderDate: -1, // Sort
amount: 1 // Range
})
// Sorgu örneği
db.orders.find({
status: "active", // Equality match
amount: { $gte: 100, $lte: 1000 } // Range query
}).sort({ orderDate: -1 }) // Sort
Cardinality-Based Ordering
// Doğru yaklaşım (userId daha unique)
db.users.createIndex({ userId: 1, status: 1 })
// Daha az etkili (status daha az unique)
db.users.createIndex({ status: 1, userId: 1 })
2. Performans Optimizasyonu Stratejileri
Covered Queries
// Index oluşturma
db.users.createIndex({ username: 1, email: 1 })
// Covered query (tüm alanlar index'te mevcut)
db.users.find(
{ username: "john_doe" },
{ _id: 0, username: 1, email: 1 }
)
Partial Indexes
// Sadece aktif kullanıcılar için index
db.users.createIndex(
{ lastLogin: 1 },
{
partialFilterExpression: {
status: "active"
}
}
)
Sparse Indexes
// Null değeri olmayan email alanları için index
db.users.createIndex(
{ email: 1 },
{ sparse: true }
)
3. Index Yönetim Stratejileri
Index Kullanım Analizi
// Index kullanımını kontrol etme
db.collection.aggregate([
{ $indexStats: {} }
])
// Sorgu planı analizi
db.collection.find({...}).explain("executionStats")
Kullanılmayan Indexleri Tespit Etme
// Index istatistikleri
db.collection.aggregate([
{ $indexStats: {} }
]).forEach((stat) => {
if (stat.accesses.ops === 0) {
print(`Unused index: ${stat.name}`)
}
})
4. Memory ve Disk Optimizasyonu
Background Indexing
// Arka planda index oluşturma
db.collection.createIndex(
{ field: 1 },
{ background: true }
)
Index Boyut Analizi
// Index boyutlarını görüntüleme
db.collection.stats().indexSizes
5. Pratik Uygulama Örnekleri
E-ticaret Uygulaması İçin Index Stratejisi
// Ürün araması için
db.products.createIndex({
category: 1,
brand: 1,
price: 1
})
// Stok takibi için partial index
db.products.createIndex(
{ stock: 1 },
{
partialFilterExpression: {
stock: { $lt: 10 }
}
}
)
// Metin araması için
db.products.createIndex({
name: "text",
description: "text"
}, {
weights: {
name: 10,
description: 5
}
})
Sosyal Medya Uygulaması İçin Index Stratejisi
// Kullanıcı timeline'ı için
db.posts.createIndex({
userId: 1,
createdAt: -1
})
// Hashtag araması için
db.posts.createIndex({
hashtags: 1,
createdAt: -1
})
// Konum bazlı aramalar için
db.posts.createIndex({
location: "2dsphere"
})
6. Best Practices
1. Index Tasarımı İçin Kurallar
- Her sorgu paterni için uygun index planlayın
- Compound indexlerde sıralamaya dikkat edin
- Gereksiz index oluşturmaktan kaçının
- Regular olarak index kullanımını analiz edin
2. Performans İzleme
// Sorgu performans analizi
const analyzeSlow = db.getSiblingDB('admin')
.system.profile.find({
millis: { $gt: 100 }
}).pretty()
3. Maintenance Stratejileri
// Index rebuild
db.collection.reIndex()
// Index kullanım istatistikleri
db.collection.aggregate([
{ $indexStats: {} }
])
7. Yaygın Hatalar ve Çözümleri
1. Aşırı Indexleme
// Kötü: Çok fazla benzer index
db.users.createIndex({ email: 1 })
db.users.createIndex({ email: 1, status: 1 })
db.users.createIndex({ email: 1, status: 1, age: 1 })
// İyi: Tek bir compound index
db.users.createIndex({ email: 1, status: 1, age: 1 })
2. Yetersiz Index Kullanımı
// Yetersiz: Sık kullanılan sorgu için index yok
db.orders.find({
status: "pending",
createdAt: { $gte: new Date('2024-01-01') }
}).sort({ amount: -1 })
// Çözüm: Uygun compound index oluşturma
db.orders.createIndex({
status: 1,
createdAt: 1,
amount: -1
})
8. İleri Seviye Optimizasyon Teknikleri
1. Index Intersection Optimizasyonu
// İki ayrı index yerine
db.collection.createIndex({ field1: 1 })
db.collection.createIndex({ field2: 1 })
// Tek bir compound index kullanın
db.collection.createIndex({ field1: 1, field2: 1 })
2. Write/Read Dengesi
// Yazma ağırlıklı operasyonlar için
db.collection.createIndex({
timestamp: 1
}, {
expireAfterSeconds: 86400 // 24 saat
})
9. Monitoring ve Bakım
Regular Kontroller
- Index Boyutu Kontrolü
db.collection.stats().indexSizes
- Index Kullanım Analizi
db.collection.aggregate([
{ $indexStats: {} }
])
- Performans Metriklerini İzleme
db.serverStatus().metrics.queryExecutor
Bu stratejiler ve best practice’ler, MongoDB’de optimum performans için kritik öneme sahiptir. Her uygulamanın kendine özgü ihtiyaçları olduğunu unutmayın ve bu prensipleri kendi kullanım senaryonuza göre uyarlayın.
explain() kullanımı ve sorgu optimizasyonu
explain() Metodunun Temel Kullanımı
explain() metodu, MongoDB’de sorgu performansını analiz etmek ve optimize etmek için kullanılan güçlü bir araçtır. Üç farklı modda çalışır:
- queryPlanner (varsayılan)
- executionStats
- allPlansExecution
Temel Syntax
// Temel kullanım
db.collection.find({}).explain()
// Belirli bir mod ile kullanım
db.collection.find({}).explain("executionStats")
explain() Modları Detaylı İnceleme
1. queryPlanner Modu
// queryPlanner kullanımı
db.users.find({ age: { $gt: 25 } }).explain("queryPlanner")
// Örnek çıktı analizi
{
"queryPlanner": {
"plannerVersion": 1,
"namespace": "test.users",
"indexFilterSet": false,
"parsedQuery": {
"age": { "$gt": 25 }
},
"winningPlan": {
"stage": "COLLSCAN", // Collection Scan - İdeal değil
"filter": {
"age": { "$gt": 25 }
}
},
"rejectedPlans": []
}
}
2. executionStats Modu
// executionStats kullanımı
db.users.find({ email: "test@example.com" }).explain("executionStats")
// Önemli metrikler
{
"executionStats": {
"executionSuccess": true,
"nReturned": 1, // Dönen döküman sayısı
"executionTimeMillis": 5, // Toplam çalışma süresi
"totalKeysExamined": 1, // İncelenen index sayısı
"totalDocsExamined": 1, // İncelenen döküman sayısı
"executionStages": {
"stage": "FETCH",
"nReturned": 1,
"executionTimeMillisEstimate": 0
}
}
}
3. allPlansExecution Modu
// allPlansExecution kullanımı
db.users.find({
age: { $gt: 25 },
status: "active"
}).explain("allPlansExecution")
Sorgu Optimizasyonu Teknikleri
1. Index Kullanımını Optimize Etme
// İndex kullanımını kontrol etme
db.users.find({
age: { $gt: 25 },
status: "active"
}).explain("executionStats")
// İndex oluşturma
db.users.createIndex({ age: 1, status: 1 })
// Optimize edilmiş sorguyu kontrol etme
db.users.find({
age: { $gt: 25 },
status: "active"
}).sort({ age: 1 }).explain("executionStats")
2. Covered Query Optimizasyonu
// Covered query örneği
db.users.createIndex({ email: 1, username: 1 })
// İdeal covered query
db.users.find(
{ email: "test@example.com" },
{ _id: 0, email: 1, username: 1 }
).explain("executionStats")
3. Sorgu Seçiciliği (Query Selectivity)
// Düşük seçicilik
db.users.find({
status: "active" // Çok sayıda eşleşme
}).explain()
// Yüksek seçicilik
db.users.find({
email: "specific@example.com" // Benzersiz değer
}).explain()
Pratik Optimizasyon Örnekleri
1. Aggregation Pipeline Optimizasyonu
// Pipeline analizi
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$userId", total: { $sum: "$amount" } } }
]).explain("executionStats")
// Optimize edilmiş versiyon
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $project: { userId: 1, amount: 1 } },
{ $group: { _id: "$userId", total: { $sum: "$amount" } } }
]).explain("executionStats")
2. Sort Optimizasyonu
// Sort performans analizi
db.products.find()
.sort({ price: -1 })
.explain("executionStats")
// Sort için index oluşturma
db.products.createIndex({ price: -1 })
// Optimize edilmiş sort
db.products.find()
.sort({ price: -1 })
.hint({ price: -1 })
.explain("executionStats")
Performans Metrikleri Analizi
1. Temel Metrikler
{
"nReturned": 100, // Dönen döküman sayısı
"executionTimeMillis": 10, // Toplam süre
"totalKeysExamined": 100, // İncelenen index sayısı
"totalDocsExamined": 100, // İncelenen döküman sayısı
}
2. İdeal Metrik Oranları
// İdeal durumlar:
// 1. totalKeysExamined ≈ nReturned
// 2. totalDocsExamined ≈ nReturned
// 3. executionTimeMillis < kabul edilebilir eşik
Optimizasyon Best Practices
1. Regular Performans Kontrolü
// Yavaş sorguları belirleme
db.getSiblingDB('admin').system.profile.find({
millis: { $gt: 100 }
}).pretty()
2. Index Kullanım Analizi
// Index kullanım istatistikleri
db.collection.aggregate([
{ $indexStats: {} }
])
3. Sorgu Planı Önbelleği
// Plan önbelleği istatistikleri
db.serverStatus().metrics.queryExecutor
Yaygın Sorunlar ve Çözümleri
1. COLLSCAN Tespiti
// COLLSCAN problemi
db.users.find({
lastName: "Smith"
}).explain().queryPlanner.winningPlan.stage
// Çözüm: İndex oluşturma
db.users.createIndex({ lastName: 1 })
2. Aşırı Index Kullanımı
// Index boyutlarını kontrol etme
db.collection.stats().indexSizes
// Kullanılmayan indexleri tespit etme
db.collection.aggregate([
{ $indexStats: {} }
]).forEach((stat) => {
if (stat.accesses.ops === 0) {
print(`Unused index: ${stat.name}`)
}
})
İleri Seviye Optimizasyon
1. Hint() Kullanımı
// Belirli bir index'i zorla kullanma
db.users.find({
age: { $gt: 25 },
status: "active"
}).hint({ age: 1, status: 1 }).explain()
2. $natural Operatörü
// Natural order scanning
db.collection.find().sort({ $natural: 1 }).explain()
Bu bilgiler, MongoDB’de sorgu optimizasyonu ve explain() kullanımı için temel bir çerçeve sunar. Her uygulamanın kendine özgü ihtiyaçları olduğunu unutmayın ve bu teknikleri kendi kullanım senaryonuza göre uyarlayın.
Schema Design
Embedded vs Referenced ilişkiler
1. Temel Kavramlar
Embedded (Gömülü) İlişkiler
- Belgeleri tek bir dokümanda birleştirir
- Veriye tek sorguda erişim sağlar
- Atomik operasyonları destekler
- “One-to-Few” ilişkiler için idealdir
Referenced (Referanslı) İlişkiler
- Belgeleri ayrı koleksiyonlarda tutar
- ObjectId referansları ile ilişkilendirir
- Veri tekrarını önler
- “One-to-Many” ve “Many-to-Many” ilişkiler için idealdir
2. Embedded İlişki Örnekleri
Basit Embedded Döküman
// Kullanıcı ve adresi - Embedded
db.users.insertOne({
name: "John Doe",
email: "john@example.com",
address: {
street: "123 Main St",
city: "New York",
country: "USA",
postalCode: "10001"
}
})
Embedded Array
// Kullanıcı ve siparişleri - Embedded Array
db.users.insertOne({
name: "Jane Smith",
email: "jane@example.com",
orders: [
{
orderId: "ORD001",
date: new Date("2024-02-01"),
items: ["Product A", "Product B"],
total: 150
},
{
orderId: "ORD002",
date: new Date("2024-02-15"),
items: ["Product C"],
total: 75
}
]
})
3. Referenced İlişki Örnekleri
Temel Referanslı İlişki
// Kullanıcı koleksiyonu
db.users.insertOne({
_id: ObjectId("user123"),
name: "Alice Johnson",
email: "alice@example.com"
})
// Siparişler koleksiyonu
db.orders.insertMany([
{
_id: ObjectId("order1"),
userId: ObjectId("user123"),
items: ["Product X"],
total: 100
},
{
_id: ObjectId("order2"),
userId: ObjectId("user123"),
items: ["Product Y", "Product Z"],
total: 200
}
])
İki Yönlü Referans
// Öğrenci koleksiyonu
db.students.insertOne({
_id: ObjectId("student1"),
name: "Bob Wilson",
courseIds: [ObjectId("course1"), ObjectId("course2")]
})
// Kurs koleksiyonu
db.courses.insertOne({
_id: ObjectId("course1"),
name: "Mathematics",
studentIds: [ObjectId("student1"), ObjectId("student2")]
})
4. Karşılaştırmalı Senaryolar
E-ticaret Uygulaması Örneği
Embedded Yaklaşım
// Ürün ve yorumları - Embedded
db.products.insertOne({
name: "Smartphone XYZ",
price: 999,
reviews: [
{
userId: ObjectId("user1"),
rating: 5,
comment: "Great product!"
},
{
userId: ObjectId("user2"),
rating: 4,
comment: "Good but expensive"
}
]
})
Referenced Yaklaşım
// Ürün
db.products.insertOne({
_id: ObjectId("prod1"),
name: "Smartphone XYZ",
price: 999
})
// Yorumlar ayrı koleksiyonda
db.reviews.insertMany([
{
productId: ObjectId("prod1"),
userId: ObjectId("user1"),
rating: 5,
comment: "Great product!"
},
{
productId: ObjectId("prod1"),
userId: ObjectId("user2"),
rating: 4,
comment: "Good but expensive"
}
])
5. Seçim Kriterleri
Embedded İlişki İçin Uygun Durumlar
- Veriler her zaman birlikte sorgulanıyorsa
- “One-to-Few” ilişkiler (1:1 veya 1:az sayıda)
- Veri tutarlılığı önemliyse
- Okuma performansı kritikse
Referenced İlişki İçin Uygun Durumlar
- Büyük veri setleri
- “One-to-Many” veya “Many-to-Many” ilişkiler
- Veri bağımsız olarak güncelleniyorsa
- Veri paylaşımı önemliyse
6. Hibrit Yaklaşım
// Hibrit model örneği - Blog uygulaması
db.posts.insertOne({
title: "MongoDB Schema Design",
content: "Full content here...",
author: { // Embedded yazar bilgisi
_id: ObjectId("author1"),
name: "John Doe",
email: "john@example.com"
},
comments: [ // Referenced yorumlar
ObjectId("comment1"),
ObjectId("comment2")
],
recentComments: [ // Son 3 yorum embedded
{
userId: ObjectId("user1"),
text: "Great post!"
}
]
})
7. Performans Karşılaştırması
Embedded İlişki Sorguları
// Tek sorguda tüm bilgileri alma
db.users.findOne({
_id: ObjectId("user123")
})
Referenced İlişki Sorguları
// İki sorgu gerekiyor
const user = await db.users.findOne({
_id: ObjectId("user123")
})
const orders = await db.orders.find({
userId: user._id
}).toArray()
8. Veri Güncelleme Stratejileri
Embedded Güncelleme
// Gömülü döküman güncelleme
db.users.updateOne(
{ _id: ObjectId("user123") },
{
$set: {
"address.city": "Los Angeles"
}
}
)
Referenced Güncelleme
// İlişkili döküman güncelleme
db.orders.updateMany(
{ userId: ObjectId("user123") },
{
$set: {
status: "processed"
}
}
)
9. Best Practices
Veri Boyutu Kontrolü
- BSON döküman limiti: 16MB
- Embedded dökümanlar için büyüme tahminleri yapın
İlişki Analizi
- İlişki türünü belirleyin (1:1, 1:N, N:M)
- Veri erişim paternlerini analiz edin
Denormalizasyon Stratejisi
- Okuma/yazma oranını değerlendirin
- Veri tutarlılığı gereksinimlerini belirleyin
Performans Optimizasyonu
- İndexleme stratejisini belirleyin
- Sorgu paternlerini optimize edin
Bu bilgiler MongoDB’de ilişki tasarımı için temel bir çerçeve sunar. Her uygulamanın kendine özgü ihtiyaçları olduğunu unutmayın ve bu yaklaşımları kendi kullanım senaryonuza göre uyarlayın.
One-to-One ilişkiler
1. One-to-One İlişki Nedir?
One-to-One (1:1) ilişki, bir koleksiyondaki bir dökümanın başka bir koleksiyondaki sadece bir dökümanla ilişkili olduğu durumu ifade eder. Bu ilişki türü iki farklı şekilde modellenebilir:
- Embedded (Gömülü) Documents
- Document References (Döküman Referansları)
2. Embedded One-to-One İlişkiler
Temel Yapı
// Kullanıcı ve profil bilgisi - Embedded
db.users.insertOne({
name: "John Doe",
email: "john@example.com",
profile: {
birthDate: new Date("1990-01-01"),
address: {
street: "123 Main St",
city: "New York",
country: "USA"
},
phoneNumber: "+1-555-123-4567",
bio: "Software Developer"
}
})
Ne Zaman Kullanılmalı?
- Veriler her zaman birlikte sorgulanıyorsa
- Veri büyüklüğü kontrol edilebilir durumdaysa
- Atomik güncellemeler gerekiyorsa
Avantajları
- Tek sorguda tüm bilgilere erişim
- Daha iyi okuma performansı
- Atomik operasyonlar için uygun
Dezavantajları
- Veri tekrarı olabilir
- BSON döküman boyut limiti (16MB)
- Bağımsız sorgulama zorluğu
3. Referenced One-to-One İlişkiler
Temel Yapı
// Kullanıcı koleksiyonu
db.users.insertOne({
_id: ObjectId("user123"),
name: "John Doe",
email: "john@example.com",
profileId: ObjectId("profile123")
})
// Profil koleksiyonu
db.profiles.insertOne({
_id: ObjectId("profile123"),
userId: ObjectId("user123"),
birthDate: new Date("1990-01-01"),
address: {
street: "123 Main St",
city: "New York",
country: "USA"
},
phoneNumber: "+1-555-123-4567",
bio: "Software Developer"
})
Ne Zaman Kullanılmalı?
- Büyük veri setleri söz konusuysa
- Veriler bağımsız olarak sorgulanacaksa
- Veri büyüklüğü değişkense
db.customers.insertOne({
name: "Alice Johnson",
email: "alice@example.com",
billingAddress: {
street: "456 Oak Avenue",
city: "Los Angeles",
state: "CA",
zipCode: "90001",
country: "USA",
isVerified: true,
lastUpdated: new Date()
}
})
4. Pratik Örnekler
E-ticaret Uygulaması: Kullanıcı ve Fatura Adresi
Embedded Yaklaşım
Referenced Yaklaşım
// Müşteri
db.customers.insertOne({
_id: ObjectId("cust123"),
name: "Alice Johnson",
email: "alice@example.com",
billingAddressId: ObjectId("addr123")
})
// Fatura adresi
db.addresses.insertOne({
_id: ObjectId("addr123"),
customerId: ObjectId("cust123"),
street: "456 Oak Avenue",
city: "Los Angeles",
state: "CA",
zipCode: "90001",
country: "USA",
isVerified: true,
lastUpdated: new Date()
})
5. Sorgu Örnekleri
Embedded Sorgu
// Kullanıcı ve profil bilgilerini tek sorguda alma
db.users.findOne(
{ email: "john@example.com" },
{ name: 1, "profile.address": 1 }
)
Referenced Sorgu
// İki adımlı sorgu
async function getUserWithProfile(email) {
const user = await db.users.findOne({ email: email });
if (user) {
const profile = await db.profiles.findOne({ _id: user.profileId });
return { ...user, profile };
}
return null;
}
6. Veri Güncelleme Stratejileri
Embedded Güncelleme
// Profil bilgisini güncelleme
db.users.updateOne(
{ email: "john@example.com" },
{
$set: {
"profile.address.city": "San Francisco",
"profile.phoneNumber": "+1-555-987-6543"
}
}
)
Referenced Güncelleme
// Profil bilgisini güncelleme
db.profiles.updateOne(
{ userId: ObjectId("user123") },
{
$set: {
"address.city": "San Francisco",
phoneNumber: "+1-555-987-6543"
}
}
)
7. Schema Validation Örnekleri
Embedded Validation
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email", "profile"],
properties: {
name: {
bsonType: "string",
description: "must be a string"
},
email: {
bsonType: "string",
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
},
profile: {
bsonType: "object",
required: ["birthDate", "address"],
properties: {
birthDate: {
bsonType: "date"
},
address: {
bsonType: "object",
required: ["street", "city", "country"]
}
}
}
}
}
}
})
Referenced Validation
db.createCollection("profiles", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["userId", "birthDate", "address"],
properties: {
userId: {
bsonType: "objectId"
},
birthDate: {
bsonType: "date"
},
address: {
bsonType: "object",
required: ["street", "city", "country"]
}
}
}
}
})
8. Best Practices
İlişki Türünü Belirleme
- Veri büyüklüğünü analiz edin
- Sorgu paternlerini değerlendirin
- Güncelleme sıklığını göz önünde bulundurun
Performans Optimizasyonu
- Uygun indexleri oluşturun
- Sorgu desenlerini optimize edin
- Veri büyüme hızını takip edin
Veri Tutarlılığı
- Validation kuralları belirleyin
- Referans bütünlüğünü koruyun
- Güncelleme stratejilerini planlayın
Monitoring
- Sorgu performansını izleyin
- Veri büyüklüğünü kontrol edin
- İndex kullanımını analiz edin
Bu bilgiler MongoDB’de One-to-One ilişki tasarımı için temel bir çerçeve sunar. Her uygulamanın kendine özgü ihtiyaçları olduğunu unutmayın ve bu yaklaşımları kendi kullanım senaryonuza göre uyarlayın.
One-to-Many ilişkiler
1. One-to-Many İlişki Türleri
MongoDB’de One-to-Many ilişkiler üç farklı şekilde modellenebilir:
- Embedded Documents (Gömülü Dökümanlar)
- Document References (Döküman Referansları)
- Denormalized References (Denormalize Edilmiş Referanslar)
2. Embedded Documents Yaklaşımı
Örnek Model: Blog ve Yorumlar
// Blog post with embedded comments
db.posts.insertOne({
title: "MongoDB Schema Design",
author: "John Doe",
content: "Content here...",
comments: [
{
user: "Alice",
text: "Great post!",
date: new Date("2024-02-01")
},
{
user: "Bob",
text: "Very helpful",
date: new Date("2024-02-02")
}
]
})
Ne Zaman Kullanılmalı?
- İlişkili veriler genellikle birlikte sorgulanıyorsa
- Alt dökümanların sayısı kontrol edilebilir durumdaysa
- Veri tutarlılığı önemliyse
Avantajları ve Dezavantajları
// Avantaj: Tek sorguda tüm verilere erişim
db.posts.findOne(
{ title: "MongoDB Schema Design" },
{ comments: { $slice: -5 } } // Son 5 yorumu getir
)
// Dezavantaj: Alt döküman güncellemesi
db.posts.updateOne(
{
"comments.user": "Alice"
},
{
$set: {
"comments.$.text": "Updated comment"
}
}
)
3. Document References Yaklaşımı
Örnek Model: E-ticaret Siparişleri
// Müşteri koleksiyonu
db.customers.insertOne({
_id: ObjectId("cust123"),
name: "John Doe",
email: "john@example.com"
})
// Siparişler koleksiyonu
db.orders.insertMany([
{
_id: ObjectId("ord1"),
customerId: ObjectId("cust123"),
orderDate: new Date(),
total: 100,
items: ["Product A", "Product B"]
},
{
_id: ObjectId("ord2"),
customerId: ObjectId("cust123"),
orderDate: new Date(),
total: 150,
items: ["Product C"]
}
])
Sorgulama Örnekleri
// Bir müşterinin tüm siparişlerini bulma
async function getCustomerOrders(customerId) {
const customer = await db.customers.findOne(
{ _id: ObjectId(customerId) }
);
const orders = await db.orders.find(
{ customerId: ObjectId(customerId) }
).toArray();
return { customer, orders };
}
// Aggregation pipeline ile sorgulama
db.orders.aggregate([
{
$match: {
customerId: ObjectId("cust123")
}
},
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
}
])
4. Denormalized References Yaklaşımı
Örnek Model: Kurs ve Öğrenciler
// Kurs koleksiyonu
db.courses.insertOne({
_id: ObjectId("course1"),
name: "MongoDB Basics",
students: [
{
_id: ObjectId("student1"),
name: "Alice Johnson",
email: "alice@example.com"
},
{
_id: ObjectId("student2"),
name: "Bob Smith",
email: "bob@example.com"
}
]
})
// Öğrenci koleksiyonu
db.students.insertMany([
{
_id: ObjectId("student1"),
name: "Alice Johnson",
email: "alice@example.com",
courses: [
{
_id: ObjectId("course1"),
name: "MongoDB Basics"
}
]
}
])
5. Karmaşık Örnek: Sosyal Medya Platformu
Kullanıcı ve Gönderiler
// Kullanıcılar
db.users.insertOne({
_id: ObjectId("user1"),
username: "john_doe",
profile: {
name: "John Doe",
bio: "Software Developer"
}
})
// Gönderiler
db.posts.insertOne({
_id: ObjectId("post1"),
userId: ObjectId("user1"),
content: "Hello MongoDB!",
likes: [
{
userId: ObjectId("user2"),
timestamp: new Date()
}
],
comments: [
{
_id: ObjectId("comment1"),
userId: ObjectId("user3"),
text: "Nice post!",
timestamp: new Date()
}
]
})
6. Performans Optimizasyonu
İndexleme Stratejileri
// Referans alanları için index
db.orders.createIndex({ customerId: 1 })
// Compound index örneği
db.orders.createIndex({
customerId: 1,
orderDate: -1
})
// Text search için index
db.posts.createIndex({
content: "text"
})
Pagination İmplementasyonu
// Sayfalama örneği
const pageSize = 10;
const page = 1;
db.orders.find({ customerId: ObjectId("cust123") })
.sort({ orderDate: -1 })
.skip(pageSize * (page - 1))
.limit(pageSize)
7. Veri Tutarlılığı
Transactions Kullanımı
// Sipariş ve stok güncelleme
const session = await client.startSession();
session.startTransaction();
try {
await db.orders.insertOne({
customerId: ObjectId("cust123"),
items: ["Product A"]
}, { session });
await db.inventory.updateOne(
{ productId: "Product A" },
{ $inc: { stock: -1 } },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
}
8. Best Practices
İlişki Türü Seçimi
- Veri büyüklüğünü değerlendirin
- Sorgu paternlerini analiz edin
- Güncelleme sıklığını göz önünde bulundurun
Performans Optimizasyonu
- Uygun indexler oluşturun
- Sayfalama implementasyonu yapın
- Büyük veri setleri için chunking kullanın
Veri Tutarlılığı
- İşlemler için transactions kullanın
- Referans bütünlüğünü koruyun
- Validation kuralları belirleyin
Monitoring
- Query performansını izleyin
- İndex kullanımını takip edin
- Veri büyüme hızını kontrol edin
Bu bilgiler MongoDB’de One-to-Many ilişki tasarımı için kapsamlı bir çerçeve sunar. Her uygulamanın kendine özgü ihtiyaçları olduğunu unutmayın ve bu yaklaşımları kendi kullanım senaryonuza göre uyarlayın.
Many-to-Many ilişkiler
Many-to-Many ilişkiler, iki koleksiyon arasında çoklu eşleşmelerin olduğu durumlarda kullanılır. Örneğin, bir öğrencinin birden fazla derse kayıt olabildiği ve bir dersin birden fazla öğrencisi olabildiği bir senaryo düşünelim.
Temel Yaklaşımlar
MongoDB’de Many-to-Many ilişkileri modellemek için iki temel yaklaşım vardır:
- Referanslar Kullanarak (References)
- Gömülü Dokümanlar Kullanarak (Embedded Documents)
1. Referanslar Kullanarak Modelleme
Bu yaklaşımda, her iki koleksiyonda da diğer koleksiyona referanslar tutulur. İşte bir örnek:
// Öğrenci Koleksiyonu
{
_id: ObjectId("5c9"),
name: "Ahmet Yılmaz",
email: "ahmet@email.com",
enrolledCourses: [
ObjectId("1a1"), // Matematik dersi
ObjectId("1a2") // Fizik dersi
]
}
// Ders Koleksiyonu
{
_id: ObjectId("1a1"),
name: "Matematik",
code: "MATH101",
enrolledStudents: [
ObjectId("5c9"), // Ahmet Yılmaz
ObjectId("5c8") // Başka bir öğrenci
]
}
Bu yaklaşımın avantajları:
- Veri tutarlılığı daha kolay sağlanır
- Bellek kullanımı daha verimlidir
- Büyük ölçekli uygulamalar için daha uygundur
Dezavantajları:
- Her ilişki için ek sorgu gerektirir
- Performans açısından daha maliyetli olabilir
2. Gömülü Dokümanlar Kullanarak Modelleme
Bu yaklaşımda, ilişkili veriler doğrudan dökümanın içine gömülür:
// Öğrenci Koleksiyonu
{
_id: ObjectId("5c9"),
name: "Ahmet Yılmaz",
email: "ahmet@email.com",
enrolledCourses: [
{
courseId: ObjectId("1a1"),
name: "Matematik",
code: "MATH101",
enrollmentDate: ISODate("2024-02-09")
},
{
courseId: ObjectId("1a2"),
name: "Fizik",
code: "PHY101",
enrollmentDate: ISODate("2024-02-09")
}
]
}
Bu yaklaşımın avantajları:
- Tek sorguda tüm ilişkili verilere erişilebilir
- Daha iyi okuma performansı sağlar
- Daha az join işlemi gerektirir
Dezavantajları:
- Veri tekrarı olabilir
- Bellek kullanımı daha fazla olabilir
- Güncellemeler daha karmaşık olabilir
Ara Koleksiyon Kullanımı
Bazen ilişki hakkında ek bilgiler tutmak gerekebilir. Bu durumda üçüncü bir koleksiyon kullanmak daha uygun olabilir:
// Enrollment Koleksiyonu
{
_id: ObjectId("7d1"),
studentId: ObjectId("5c9"),
courseId: ObjectId("1a1"),
enrollmentDate: ISODate("2024-02-09"),
grade: 85,
status: "active"
}
Bu yaklaşımın avantajları:
- İlişki hakkında detaylı bilgi tutulabilir
- Veri tutarlılığı daha kolay sağlanır
- İlişkiyi yönetmek daha kolaydır
Örnek Sorgular
İlişkili verileri çekmek için aggregation pipeline kullanabiliriz:
// Bir öğrencinin tüm derslerini getirme
db.students.aggregate([
{
$match: { _id: ObjectId("5c9") }
},
{
$lookup: {
from: "courses",
localField: "enrolledCourses",
foreignField: "_id",
as: "courseDetails"
}
}
])
// Bir dersin tüm öğrencilerini getirme
db.courses.aggregate([
{
$match: { _id: ObjectId("1a1") }
},
{
$lookup: {
from: "students",
localField: "enrolledStudents",
foreignField: "_id",
as: "studentDetails"
}
}
])
En İyi Uygulamalar
- İlişki Büyüklüğü: İlişki sayısı çok büyükse (binlerce), referans yaklaşımını tercih edin.
- Veri Güncelliği: Veriler sık güncellenmiyorsa, gömülü doküman yaklaşımı düşünülebilir.
- Sorgu Patterns: Eğer veriler genellikle birlikte sorgulanıyorsa, gömülü doküman yaklaşımı daha verimli olabilir.
- Bellek Kullanımı: Bellek kısıtlaması varsa, referans yaklaşımı daha uygundur.
- İndeksleme: İlişki alanlarını doğru şekilde indeksleyin:
// Öğrenci koleksiyonunda ders referansları için indeks
db.students.createIndex({ "enrolledCourses": 1 })
// Ders koleksiyonunda öğrenci referansları için indeks
db.courses.createIndex({ "enrolledStudents": 1 })
Bu yaklaşımlardan hangisini seçeceğiniz, uygulamanızın özel gereksinimlerine, veri büyüklüğüne, sorgu patterns’lerine ve performans ihtiyaçlarına bağlıdır.
Schema validation
Schema validation, MongoDB’de veri tutarlılığını sağlamak için kullanılan önemli bir özelliktir. Bu özellik sayesinde koleksiyonlara eklenecek veya güncellenecek dokümanların belirli bir yapıya uygun olmasını zorunlu kılabilirsiniz.
Temel Bileşenler
1. Validation Level
- strict: Tüm yazma işlemlerinde doğrulama yapılır
- moderate: Sadece mevcut geçerli dokümanlar üzerindeki güncellemelerde doğrulama yapılır
2. Validation Action
- error: Doğrulama başarısız olduğunda işlemi reddeder
- warn: Doğrulama başarısız olduğunda uyarı verir ama işlemi kabul eder
Validation Kuralları Oluşturma
JSON Schema Kullanarak Validation
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email", "age"],
properties: {
name: {
bsonType: "string",
description: "must be a string and is required"
},
email: {
bsonType: "string",
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
description: "must be a valid email address"
},
age: {
bsonType: "int",
minimum: 18,
maximum: 99,
description: "must be an integer between 18 and 99"
},
phone: {
bsonType: "string",
description: "must be a string if present"
}
}
}
},
validationLevel: "strict",
validationAction: "error"
})
Query Operator Kullanarak Validation
db.createCollection("products", {
validator: {
$and: [
{ price: { $gt: 0 } },
{ quantity: { $gte: 0 } },
{ category: { $in: ["electronics", "books", "clothing"] } },
{ status: { $in: ["active", "inactive"] } }
]
}
})
Mevcut Koleksiyona Validation Ekleme
db.runCommand({
collMod: "users",
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: {
bsonType: "string",
description: "must be a string and is required"
},
email: {
bsonType: "string",
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
description: "must be a valid email address"
}
}
}
},
validationLevel: "moderate"
})
Kompleks Validation Örnekleri
İç İçe Objeler için Validation
db.createCollection("orders", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["orderNumber", "customer", "items"],
properties: {
orderNumber: {
bsonType: "string",
description: "must be a string and is required"
},
customer: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: { bsonType: "string" },
email: { bsonType: "string" },
address: {
bsonType: "object",
properties: {
street: { bsonType: "string" },
city: { bsonType: "string" },
country: { bsonType: "string" }
}
}
}
},
items: {
bsonType: "array",
minItems: 1,
items: {
bsonType: "object",
required: ["productId", "quantity", "price"],
properties: {
productId: { bsonType: "objectId" },
quantity: { bsonType: "int", minimum: 1 },
price: { bsonType: "decimal" }
}
}
}
}
}
}
})
Conditional Validation
db.createCollection("employees", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "position", "salary"],
properties: {
name: { bsonType: "string" },
position: { bsonType: "string" },
salary: { bsonType: "decimal" },
department: { bsonType: "string" },
manager: {
bsonType: ["object", "null"],
properties: {
name: { bsonType: "string" },
id: { bsonType: "objectId" }
}
}
},
allOf: [
{
if: {
properties: {
position: { enum: ["manager", "director"] }
}
},
then: {
required: ["department"]
}
}
]
}
}
})
Validation İpuçları ve En İyi Uygulamalar
Kademeli Geçiş:
- Yeni validation kuralları eklerken
validationLevel: "moderate"
kullanın - Mevcut verileri yeni kurallara uygun hale getirin
- Sonra
validationLevel: "strict"
geçiş yapın
Performans:
// İndeksler ile validation kurallarını eşleştirin
db.users.createIndex({ "email": 1 }, { unique: true })
Hata Yönetimi:
try {
db.users.insertOne({
name: "John Doe",
email: "invalid-email" // Validation hatası üretecek
})
} catch (error) {
print("Validation error:", error.message)
}
Validation Bilgilerini Görüntüleme:
db.getCollectionInfos({
name: "users"
})[0].options.validator
Validation Devre Dışı Bırakma:
db.runCommand({
collMod: "users",
validator: {},
validationLevel: "off"
})
Bu schema validation özellikleri, MongoDB’de veri tutarlılığını sağlamak için güçlü bir araç sunar. Özellikle büyük uygulamalarda ve ekip çalışmalarında, veri yapısının tutarlı kalmasını sağlamak için çok önemlidir.
Denormalizasyon stratejileri
Denormalizasyon, veri tekrarına izin vererek sorgu performansını artırmayı amaçlayan bir yaklaşımdır. MongoDB’de denormalizasyon stratejileri, uygulamanın ihtiyaçlarına göre şekillendirilir.
1. One-To-One İlişkilerde Denormalizasyon
Bu strateji, birbiriyle yakından ilişkili verileri tek bir dokümanda birleştirmeyi içerir.
// Normalize edilmiş hali (iki ayrı koleksiyon)
// users koleksiyonu
{
_id: ObjectId("1"),
name: "Ahmet Yılmaz",
email: "ahmet@email.com"
}
// user_details koleksiyonu
{
_id: ObjectId("101"),
user_id: ObjectId("1"),
address: "İstanbul",
phone: "5551234567"
}
// Denormalize edilmiş hali (tek koleksiyon)
{
_id: ObjectId("1"),
name: "Ahmet Yılmaz",
email: "ahmet@email.com",
details: {
address: "İstanbul",
phone: "5551234567"
}
}
Avantajları:
- Tek sorguda tüm bilgilere erişim
- Join operasyonlarına gerek kalmaması
- Daha iyi okuma performansı
Dezavantajları:
- Veri tekrarı
- Güncelleme işlemlerinin daha karmaşık olması
2. One-To-Many İlişkilerde Denormalizasyon
2.1 Gömülü Dizi Yaklaşımı
// Bir blog yazısı ve yorumları
{
_id: ObjectId("1"),
title: "MongoDB'de Denormalizasyon",
content: "...",
author: "Mehmet",
comments: [
{
user: "Ali",
text: "Harika bir yazı!",
date: ISODate("2024-02-09")
},
{
user: "Ayşe",
text: "Çok faydalı.",
date: ISODate("2024-02-09")
}
]
}
2.2 Referans ve Kopya Yaklaşımı
// products koleksiyonu
{
_id: ObjectId("1"),
name: "Laptop",
price: 15000,
category: {
_id: ObjectId("c1"),
name: "Elektronik", // Kategori bilgisi kopyalanmış
path: "/elektronik/bilgisayarlar"
}
}
// categories koleksiyonu
{
_id: ObjectId("c1"),
name: "Elektronik",
path: "/elektronik/bilgisayarlar",
description: "Elektronik ürünler"
}
3. Many-To-Many İlişkilerde Denormalizasyon
3.1 Çift Yönlü Gömme
// books koleksiyonu
{
_id: ObjectId("b1"),
title: "MongoDB Basics",
authors: [
{
_id: ObjectId("a1"),
name: "John Doe",
email: "john@email.com" // Kopyalanmış bilgi
}
]
}
// authors koleksiyonu
{
_id: ObjectId("a1"),
name: "John Doe",
email: "john@email.com",
books: [
{
_id: ObjectId("b1"),
title: "MongoDB Basics" // Kopyalanmış bilgi
}
]
}
4. Hesaplanmış Alanlar Stratejisi
Bu strateji, sık kullanılan hesaplamaların sonuçlarını saklar.
// orders koleksiyonu
{
_id: ObjectId("o1"),
items: [
{ product: "A", price: 100, quantity: 2 },
{ product: "B", price: 150, quantity: 1 }
],
totalAmount: 350, // Önceden hesaplanmış toplam
itemCount: 3 // Önceden hesaplanmış ürün sayısı
}
5. Veri Bütünlüğünü Koruma Stratejileri
5.1 Atomik Güncellemeler
// Ürün stok güncelleme
db.products.updateOne(
{ _id: ObjectId("1") },
{
$inc: { stock: -1 },
$push: {
stockHistory: {
date: new Date(),
action: "decrease",
amount: 1
}
}
}
)
5.2 Versiyon Kontrolü
{
_id: ObjectId("1"),
name: "Ürün A",
price: 100,
version: 1, // Versiyon kontrolü için
lastUpdated: ISODate("2024-02-09")
}
// Güncelleme işlemi
db.products.updateOne(
{
_id: ObjectId("1"),
version: 1 // Mevcut versiyon kontrolü
},
{
$set: {
price: 120,
version: 2, // Versiyon artırımı
lastUpdated: new Date()
}
}
)
6. En İyi Uygulamalar
- Veri Boyutu Kontrolü:
// Doküman boyutu kontrolü
const stats = db.collection.stats()
console.log("Ortalama doküman boyutu:", stats.avgObjSize)
- Güncelleme Stratejisi:
// Toplu güncelleme için
const bulkOps = db.collection.initializeUnorderedBulkOp()
updates.forEach(update => {
bulkOps.find({ _id: update._id }).updateOne({
$set: { updatedField: update.newValue }
})
})
bulkOps.execute()
- İndeksleme:
// Sık sorgulanan denormalize alanlar için indeks
db.products.createIndex({ "category.name": 1 })
db.products.createIndex({ "comments.date": 1 })
7. Denormalizasyon Kararı Verme Kriterleri
Okuma/Yazma Oranı:
- Yüksek okuma / düşük yazma → Denormalizasyon uygun
- Yüksek yazma / düşük okuma → Normalizasyon uygun
Veri Tutarlılığı Gereksinimleri:
- Kesin tutarlılık → Normalizasyon
- Eventual consistency → Denormalizasyon uygun
Sorgu Patterns:
- Sık birlikte sorgulanan veriler → Denormalizasyon
- Bağımsız sorgulanan veriler → Normalizasyon
Veri Boyutu:
- Küçük, değişmeyen veriler → Denormalizasyon uygun
- Büyük, sık değişen veriler → Normalizasyon uygun
Bu stratejiler, uygulamanızın özel ihtiyaçlarına göre şekillendirilmeli ve performans/tutarlılık dengesi gözetilerek uygulanmalıdır.
Transactions ve Concurrency
ACID özellikleri
ACID, veritabanı işlemlerinin güvenilirliğini sağlayan dört temel özelliği temsil eder:
1. Atomicity (Atomiklik)
Atomiklik, bir transaction’ın “ya hep ya hiç” prensibiyle çalışmasını ifade eder. Transaction içindeki tüm işlemler ya başarıyla tamamlanır ya da hiçbiri gerçekleşmez.
const session = client.startSession();
session.startTransaction();
try {
// Hesaptan para çekme
await accounts.updateOne(
{ userId: "123" },
{ $inc: { balance: -100 } },
{ session }
);
// Diğer hesaba para yatırma
await accounts.updateOne(
{ userId: "456" },
{ $inc: { balance: 100 } },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
console.error("İşlem başarısız:", error);
} finally {
await session.endSession();
}
2. Consistency (Tutarlılık)
Tutarlılık, veritabanının bir transaction öncesi ve sonrasında tutarlı bir durumda olmasını sağlar. MongoDB’de bu özellik şu şekilde sağlanır:
- Write Concern ayarları
- Read Concern ayarları
- Schema Validation
// Write Concern örneği
await collection.insertOne(
{ item: "example" },
{ writeConcern: { w: "majority", wtimeout: 5000 } }
);
// Schema Validation örneği
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email", "age"],
properties: {
name: { bsonType: "string" },
email: { bsonType: "string" },
age: { bsonType: "int" }
}
}
}
});
3. Isolation (İzolasyon)
İzolasyon, eşzamanlı çalışan transaction’ların birbirini etkilememesini sağlar. MongoDB’de farklı izolasyon seviyeleri bulunur:
- Read Uncommitted
- Read Committed
- Snapshot
- Serializable
// Snapshot izolasyon seviyesi örneği
const session = client.startSession({
defaultTransactionOptions: {
readConcern: { level: "snapshot" },
writeConcern: { w: "majority" }
}
});
await session.withTransaction(async () => {
const cursor = collection.find({}, { session });
const documents = await cursor.toArray();
// İşlemler...
});
4. Durability (Dayanıklılık)
Dayanıklılık, başarıyla tamamlanan bir transaction’ın verilerinin kalıcı olarak saklanmasını garanti eder. MongoDB’de bu özellik şu şekilde sağlanır:
- Journal (Write Ahead Log)
- Replication
- Write Concern ayarları
// Dayanıklılık için Write Concern ayarı
const result = await collection.insertOne(
{ item: "example" },
{
writeConcern: {
w: "majority", // Çoğunluk onayı
j: true, // Journal'a yazılmasını bekle
wtimeout: 5000 // Timeout süresi
}
}
);
Concurrency Control (Eşzamanlılık Kontrolü)
MongoDB’de eşzamanlılık kontrolü için çeşitli mekanizmalar bulunur:
1. Optimistic Concurrency Control (İyimser Eşzamanlılık Kontrolü)
async function updateDocumentOptimistic(collection, id, update) {
const doc = await collection.findOne({ _id: id });
const version = doc.version;
const result = await collection.updateOne(
{
_id: id,
version: version // Versiyon kontrolü
},
{
$set: {
...update,
version: version + 1 // Versiyon artırımı
}
}
);
if (result.modifiedCount === 0) {
throw new Error("Concurrent modification detected");
}
}
2. Pessimistic Concurrency Control (Kötümser Eşzamanlılık Kontrolü)
const session = client.startSession();
try {
session.startTransaction();
// Dökümanı kilitle
const doc = await collection.findOne(
{ _id: id },
{ session, lock: { mode: "exclusive" } }
);
// Güncelleme işlemi
await collection.updateOne(
{ _id: id },
{ $set: update },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
Önemli Notlar ve Best Practices
- Transaction’ları mümkün olduğunca kısa tutun
- İzolasyon seviyesini ihtiyaca göre seçin
- Timeout değerlerini uygun şekilde ayarlayın
- Write Concern ve Read Concern ayarlarını doğru yapılandırın
- İndexleri etkin kullanın
- Deadlock durumlarına karşı önlem alın
Bu özellikler ve mekanizmalar sayesinde MongoDB, özellikle 4.0 sürümünden itibaren, ACID uyumlu işlemleri tam olarak destekleyerek kurumsal uygulamalar için güvenilir bir seçenek haline gelmiştir.
Multi-document transactions
Multi-document transactions, birden fazla doküman üzerinde yapılan işlemlerin atomik olarak gerçekleştirilmesini sağlar. Bu özellik MongoDB 4.0 ile replica setlerde, 4.2 ile de sharded cluster’larda kullanılabilir hale gelmiştir.
1. Temel Kavramlar ve Özellikler
Transaction Yaşam Döngüsü
- Başlatma (Start)
- İşlemler (Operations)
- Onaylama (Commit) veya İptal (Abort)
- Sonlandırma (End)
const session = client.startSession();
try {
session.startTransaction({
readPreference: 'primary',
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' }
});
// İşlemler burada gerçekleşir
await orders.insertOne({ item: "A", status: "created" }, { session });
await inventory.updateOne(
{ item: "A" },
{ $inc: { quantity: -1 } },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
2. Kompleks İşlem Örnekleri
Örnek 1: Banka Transferi İşlemi
async function transferMoney(fromAccountId, toAccountId, amount) {
const session = client.startSession();
try {
session.startTransaction();
// Gönderen hesaptan para çekme
const fromAccount = await accounts.findOneAndUpdate(
{
_id: fromAccountId,
balance: { $gte: amount }
},
{ $inc: { balance: -amount } },
{ session, returnDocument: 'after' }
);
if (!fromAccount) {
throw new Error('Yetersiz bakiye');
}
// Alıcı hesaba para yatırma
await accounts.updateOne(
{ _id: toAccountId },
{ $inc: { balance: amount } },
{ session }
);
// İşlem kaydını oluşturma
await transactions.insertOne({
fromAccount: fromAccountId,
toAccount: toAccountId,
amount: amount,
date: new Date()
}, { session });
await session.commitTransaction();
return { success: true };
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
}
Örnek 2: E-Ticaret Sipariş İşlemi
async function createOrder(userId, items) {
const session = client.startSession();
try {
session.startTransaction();
// Stok kontrolü
for (const item of items) {
const product = await products.findOne(
{
_id: item.productId,
stock: { $gte: item.quantity }
},
{ session }
);
if (!product) {
throw new Error(`Yetersiz stok: ${item.productId}`);
}
}
// Stok güncelleme
for (const item of items) {
await products.updateOne(
{ _id: item.productId },
{ $inc: { stock: -item.quantity } },
{ session }
);
}
// Sipariş oluşturma
const order = await orders.insertOne({
userId,
items,
status: 'created',
date: new Date()
}, { session });
// Kullanıcı sipariş geçmişi güncelleme
await users.updateOne(
{ _id: userId },
{ $push: { orderHistory: order.insertedId } },
{ session }
);
await session.commitTransaction();
return { success: true, orderId: order.insertedId };
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
}
3. Transaction Limitleri ve Kısıtlamalar
- Zaman Limiti: Varsayılan olarak 60 saniye
- Boyut Limiti: 16MB
- İşlem Sayısı: Maksimum 1000 işlem
- Bellek Kullanımı: 64MB
// Özel timeout ile transaction başlatma
const session = client.startSession();
session.startTransaction({
maxTimeMS: 30000, // 30 saniye timeout
writeConcern: { w: 'majority' }
});
4. Performance Optimizasyonu
Best Practices
- İşlem Süresi Optimizasyonu:
// İyi Pratik
const session = client.startSession();
try {
session.startTransaction();
// Önceden hazırlanmış veriler
const bulkOperations = documents.map(doc => ({
updateOne: {
filter: { _id: doc._id },
update: { $set: doc }
}
}));
// Bulk işlem
await collection.bulkWrite(bulkOperations, { session });
await session.commitTransaction();
} finally {
await session.endSession();
}
- İndex Kullanımı:
// İndex oluşturma
await collection.createIndexes([
{ key: { userId: 1 } },
{ key: { date: 1 } }
]);
// Transaction içinde index kullanımı
const session = client.startSession();
try {
session.startTransaction();
// İndexli sorgu
await collection.find({
userId: specificUserId,
date: { $gte: startDate }
}).hint({ userId: 1, date: 1 }).toArray();
await session.commitTransaction();
} finally {
await session.endSession();
}
5. Hata Yönetimi ve Recovery
async function retryTransaction(operation, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const session = client.startSession();
try {
session.startTransaction();
await operation(session);
await session.commitTransaction();
return true;
} catch (error) {
await session.abortTransaction();
if (attempt === maxAttempts) throw error;
// TransientTransactionError veya WriteConcernError için tekrar dene
if (error.hasErrorLabel('TransientTransactionError') ||
error.hasErrorLabel('WriteConcernError')) {
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
continue;
}
throw error;
} finally {
await session.endSession();
}
}
}
Bu multi-document transaction özellikleri sayesinde MongoDB, karmaşık iş süreçlerini güvenli ve tutarlı bir şekilde yönetebilme kabiliyeti sunmaktadır. Bu özellikler özellikle finansal işlemler, e-ticaret süreçleri ve veri bütünlüğünün kritik olduğu diğer senaryolarda büyük önem taşır.
Session kavramı
Session, MongoDB’de client ve sunucu arasındaki mantıksal bir bağlantıyı temsil eder. Sessionlar özellikle transactions, nedensel tutarlılık ve oturum bazlı işlemleri yönetmek için kullanılır.
1. Session Türleri
1.1 Explicit Sessions (Açık Oturumlar)
Kullanıcı tarafından açıkça oluşturulan ve yönetilen oturumlardır.
// Explicit Session oluşturma
const session = client.startSession();
try {
// Session ile işlemler
await collection.findOne({ _id: 1 }, { session });
} finally {
await session.endSession();
}
1.2 Implicit Sessions (Örtük Oturumlar)
MongoDB sürücüsü tarafından otomatik olarak yönetilen oturumlardır.
// Implicit Session - Otomatik yönetilir
await collection.findOne({ _id: 1 }); // Session otomatik oluşturulur
2. Session Özellikleri ve Yapılandırma
2.1 Session Seçenekleri
const session = client.startSession({
defaultTransactionOptions: {
readPreference: 'primary',
readConcern: { level: 'majority' },
writeConcern: { w: 'majority' }
},
causalConsistency: true
});
2.2 Session Durumları
const session = client.startSession();
// Session durumunu kontrol etme
console.log('Session aktif mi:', session.hasActiveTransaction());
console.log('Session ID:', session.id);
// Session süresini kontrol etme
const serverSession = session.serverSession;
console.log('Süre doldu mu:', serverSession.hasTimedOut());
3. Session Kullanım Senaryoları
3.1 Nedensel Tutarlılık (Causal Consistency)
async function causalConsistencyExample() {
const session = client.startSession({ causalConsistency: true });
try {
// İlk yazma işlemi
const writeResult = await collection.insertOne(
{ _id: 1, data: 'örnek' },
{ session }
);
// operationTime ve clusterTime alınır
const operationTime = session.operationTime;
const clusterTime = session.clusterTime;
// Sonraki okuma işlemi aynı veya daha yeni verileri görür
const readResult = await collection.findOne(
{ _id: 1 },
{
session,
readConcern: {
level: 'majority',
afterClusterTime: clusterTime
}
}
);
} finally {
await session.endSession();
}
}
3.2 Retry Logic ile Session Kullanımı
async function retryWithSession(operation) {
const session = client.startSession();
try {
let retry = true;
let retryCount = 0;
while (retry && retryCount < 3) {
try {
session.startTransaction();
await operation(session);
await session.commitTransaction();
retry = false;
} catch (error) {
retryCount++;
await session.abortTransaction();
if (error.hasErrorLabel('TransientTransactionError') &&
retryCount < 3) {
await new Promise(resolve =>
setTimeout(resolve, 1000 * retryCount)
);
continue;
}
throw error;
}
}
} finally {
await session.endSession();
}
}
4. Session Yönetimi ve Best Practices
4.1 Resource Yönetimi
class SessionManager {
constructor(client) {
this.client = client;
this.activeSessions = new Set();
}
async createSession() {
const session = this.client.startSession();
this.activeSessions.add(session);
return session;
}
async closeSession(session) {
if (session && this.activeSessions.has(session)) {
await session.endSession();
this.activeSessions.delete(session);
}
}
async closeAllSessions() {
for (const session of this.activeSessions) {
await this.closeSession(session);
}
}
}
// Kullanım örneği
const sessionManager = new SessionManager(client);
async function performOperation() {
const session = await sessionManager.createSession();
try {
// İşlemler
} finally {
await sessionManager.closeSession(session);
}
}
4.2 Session Pooling
class SessionPool {
constructor(client, poolSize = 5) {
this.client = client;
this.poolSize = poolSize;
this.sessions = [];
this.available = [];
}
async initialize() {
for (let i = 0; i < this.poolSize; i++) {
const session = this.client.startSession();
this.sessions.push(session);
this.available.push(session);
}
}
async acquireSession() {
if (this.available.length === 0) {
throw new Error('No available sessions');
}
return this.available.pop();
}
async releaseSession(session) {
if (this.sessions.includes(session)) {
this.available.push(session);
}
}
async closePool() {
for (const session of this.sessions) {
await session.endSession();
}
this.sessions = [];
this.available = [];
}
}
5. Session Monitoring ve Debugging
class SessionMonitor {
constructor() {
this.sessionStats = new Map();
}
trackSession(session) {
this.sessionStats.set(session.id, {
startTime: new Date(),
operations: 0,
lastOperation: null
});
}
recordOperation(session, operationType) {
const stats = this.sessionStats.get(session.id);
if (stats) {
stats.operations++;
stats.lastOperation = {
type: operationType,
time: new Date()
};
}
}
getSessionStats(session) {
return this.sessionStats.get(session.id);
}
cleanup(session) {
this.sessionStats.delete(session.id);
}
}
// Kullanım örneği
const monitor = new SessionMonitor();
async function monitoredOperation() {
const session = client.startSession();
monitor.trackSession(session);
try {
monitor.recordOperation(session, 'find');
await collection.findOne({}, { session });
monitor.recordOperation(session, 'insert');
await collection.insertOne({ data: 'test' }, { session });
console.log('Session İstatistikleri:',
monitor.getSessionStats(session));
} finally {
monitor.cleanup(session);
await session.endSession();
}
}
Session yönetimi, MongoDB’de veri tutarlılığı ve transaction yönetimi için kritik bir bileşendir. Doğru session yönetimi, uygulamanın performansını ve güvenilirliğini önemli ölçüde etkiler. Bu nedenle, session’ların uygun şekilde oluşturulması, yönetilmesi ve kapatılması büyük önem taşır.
Isolation levels
MongoDB’de izolasyon seviyeleri, eşzamanlı işlemlerin birbirlerini nasıl etkileyeceğini belirler. Read Concern ve Write Concern mekanizmalarıyla birlikte çalışarak veri tutarlılığını sağlar.
1. Read Isolation Levels
MongoDB’de dört temel read isolation seviyesi bulunur:
1.1 Read Uncommitted
En düşük izolasyon seviyesidir. Diğer transaction’lar tarafından henüz commit edilmemiş değişiklikleri görebilir.
const session = client.startSession();
try {
session.startTransaction({
readConcern: { level: 'local' },
writeConcern: { w: 1 }
});
const result = await collection.findOne(
{ _id: 1 },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
} finally {
await session.endSession();
}
1.2 Read Committed
Sadece commit edilmiş değişiklikleri görebilir.
const session = client.startSession();
try {
session.startTransaction({
readConcern: { level: 'majority' },
writeConcern: { w: 'majority' }
});
const result = await collection.find(
{ status: 'active' },
{ session }
).toArray();
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
} finally {
await session.endSession();
}
1.3 Snapshot
Transaction başlangıcındaki veritabanı durumunu görür.
const session = client.startSession();
try {
session.startTransaction({
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' }
});
// İlk okuma
const firstRead = await collection.findOne(
{ _id: 1 },
{ session }
);
// Aynı transaction içinde ikinci okuma
// İlk okumayla aynı snap'i görür
const secondRead = await collection.findOne(
{ _id: 1 },
{ session }
);
await session.commitTransaction();
} finally {
await session.endSession();
}
1.4 Linearizable
En yüksek izolasyon seviyesidir. Tüm okuma ve yazma işlemlerinin sıralı olarak gerçekleşmesini sağlar.
const session = client.startSession();
try {
const result = await collection.findOne(
{ _id: 1 },
{
readConcern: { level: 'linearizable' },
maxTimeMS: 5000 // Timeout setting
}
);
} finally {
await session.endSession();
}
2. Write Isolation Levels ve Conflict Resolution
2.1 Write Concern Örnekleri
// Majority Write Concern
const session = client.startSession();
try {
session.startTransaction({
writeConcern: {
w: 'majority',
wtimeout: 5000,
j: true
}
});
await collection.updateOne(
{ _id: 1 },
{ $set: { status: 'updated' } },
{ session }
);
await session.commitTransaction();
} finally {
await session.endSession();
}
2.2 Write Conflict Yönetimi
async function updateWithRetry(id, update, maxRetries = 3) {
let retryCount = 0;
while (retryCount < maxRetries) {
const session = client.startSession();
try {
session.startTransaction({
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' }
});
const doc = await collection.findOne(
{ _id: id },
{ session }
);
if (!doc) throw new Error('Document not found');
await collection.updateOne(
{ _id: id, version: doc.version },
{
$set: update,
$inc: { version: 1 }
},
{ session }
);
await session.commitTransaction();
return true;
} catch (error) {
await session.abortTransaction();
if (error.errorLabels &&
error.errorLabels.includes('TransientTransactionError')) {
retryCount++;
await new Promise(resolve =>
setTimeout(resolve, 1000 * Math.pow(2, retryCount))
);
continue;
}
throw error;
} finally {
await session.endSession();
}
}
throw new Error('Max retries exceeded');
}
3. İzolasyon Seviyesi Seçimi için Best Practices
3.1 Use Case Bazlı İzolasyon Seçimi
class TransactionManager {
static async executeReadTransaction(useCase, operation) {
const session = client.startSession();
try {
const options = this.getReadConcernForUseCase(useCase);
session.startTransaction(options);
const result = await operation(session);
await session.commitTransaction();
return result;
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
}
static getReadConcernForUseCase(useCase) {
switch(useCase) {
case 'ANALYTICS':
return {
readConcern: { level: 'local' },
writeConcern: { w: 1 }
};
case 'FINANCIAL':
return {
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' }
};
case 'AUDIT':
return {
readConcern: { level: 'linearizable' },
writeConcern: { w: 'majority' }
};
default:
return {
readConcern: { level: 'majority' },
writeConcern: { w: 'majority' }
};
}
}
}
3.2 Performance Monitoring
class IsolationLevelMonitor {
constructor() {
this.metrics = {
transactions: 0,
conflicts: 0,
retries: 0,
avgDuration: 0
};
}
async measureTransaction(operation, isolationLevel) {
const startTime = Date.now();
let retryCount = 0;
try {
const session = client.startSession();
session.startTransaction({
readConcern: { level: isolationLevel }
});
await operation(session);
await session.commitTransaction();
this.recordSuccess(Date.now() - startTime);
} catch (error) {
if (error.hasErrorLabel('TransientTransactionError')) {
this.metrics.conflicts++;
retryCount++;
}
throw error;
} finally {
this.metrics.transactions++;
this.metrics.retries += retryCount;
}
}
recordSuccess(duration) {
this.metrics.avgDuration =
(this.metrics.avgDuration * (this.metrics.transactions - 1) + duration)
/ this.metrics.transactions;
}
getMetrics() {
return {
...this.metrics,
conflictRate: this.metrics.conflicts / this.metrics.transactions,
retryRate: this.metrics.retries / this.metrics.transactions
};
}
}
4. Yaygın Sorunlar ve Çözümleri
4.1 Deadlock Yönetimi
async function executeWithDeadlockPrevention(operations) {
// Operasyonları tutarlı bir sırada sırala
const sortedOps = operations.sort((a, b) =>
a.resourceId.localeCompare(b.resourceId)
);
const session = client.startSession();
try {
session.startTransaction({
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' }
});
for (const op of sortedOps) {
await collection.updateOne(
{ _id: op.resourceId },
{ $set: op.update },
{ session }
);
}
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
}
İzolasyon seviyeleri, MongoDB’de veri tutarlılığı ve performans arasında denge kurmamızı sağlayan önemli bir mekanizmadır. Doğru izolasyon seviyesinin seçimi, uygulamanın gereksinimlerine ve kullanım senaryolarına bağlıdır. Yüksek izolasyon seviyeleri daha fazla tutarlılık sağlarken performansı etkileyebilir, düşük izolasyon seviyeleri ise daha iyi performans sunarken bazı tutarlılık garantilerinden ödün verebilir.
Locking mekanizmaları
MongoDB’de lock’lar, eşzamanlı erişimi kontrol etmek ve veri tutarlılığını sağlamak için kullanılır. Farklı granüllük seviyelerinde lock mekanizmaları sunar.
1. Lock Türleri
1.1 Global Lock
Tüm veritabanını etkileyen lock türüdür.
// Global lock gerektiren bir operasyon örneği
db.adminCommand({ fsync: 1, lock: true });
try {
// Backup işlemleri burada gerçekleştirilir
} finally {
// Global lock'u kaldır
db.fsyncUnlock();
}
1.2 Database Lock
Belirli bir veritabanı üzerinde lock oluşturur.
const session = client.startSession();
try {
session.startTransaction({
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' }
});
// Database seviyesinde exclusive lock
await db.command({
query: { _id: 1 },
$isolated: 1
}, { session });
await session.commitTransaction();
} finally {
await session.endSession();
}
1.3 Collection Lock
Koleksiyon seviyesinde lock oluşturur.
async function withCollectionLock(collectionName, operation) {
const session = client.startSession();
try {
session.startTransaction();
// Collection üzerinde write lock
await collection.findOne(
{},
{ session, lock: { mode: 'w' } }
);
await operation(session);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
}
1.4 Document Lock
Doküman seviyesinde lock oluşturur.
async function updateWithDocumentLock(documentId, update) {
const session = client.startSession();
try {
session.startTransaction();
// Doküman seviyesinde lock
const doc = await collection.findOne(
{ _id: documentId },
{ session, lock: { mode: 'w' } }
);
if (!doc) throw new Error('Document not found');
await collection.updateOne(
{ _id: documentId },
update,
{ session }
);
await session.commitTransaction();
} finally {
await session.endSession();
}
}
2. Lock Modları
2.1 Shared (S) Lock
Okuma işlemleri için kullanılır.
class SharedLockManager {
async acquireSharedLock(resourceId) {
const session = client.startSession();
try {
session.startTransaction();
const result = await collection.findOne(
{ _id: resourceId },
{
session,
lock: { mode: 'r' } // read lock
}
);
return { session, result };
} catch (error) {
await session.abortTransaction();
throw error;
}
}
}
2.2 Exclusive (X) Lock
Yazma işlemleri için kullanılır.
class ExclusiveLockManager {
async acquireExclusiveLock(resourceId) {
const session = client.startSession();
try {
session.startTransaction();
const result = await collection.findOne(
{ _id: resourceId },
{
session,
lock: { mode: 'w' } // write lock
}
);
return { session, result };
} catch (error) {
await session.abortTransaction();
throw error;
}
}
}
3. Lock Yönetimi ve Stratejileri
3.1 Intent Lock Yönetimi
class IntentLockManager {
async acquireIntentLock(collection, documentId) {
const session = client.startSession();
try {
session.startTransaction();
// Intent-exclusive lock
await collection.findOne(
{ _id: documentId },
{
session,
lock: { mode: 'ix' } // intent-exclusive
}
);
return session;
} catch (error) {
await session.abortTransaction();
throw error;
}
}
}
3.2 Deadlock Prevention
class DeadlockPreventionManager {
constructor() {
this.lockOrder = new Map();
}
async acquireLocksInOrder(resourceIds) {
// Kaynakları sırala
const sortedIds = [...resourceIds].sort();
const session = client.startSession();
try {
session.startTransaction();
for (const id of sortedIds) {
await collection.findOne(
{ _id: id },
{
session,
lock: { mode: 'w' }
}
);
}
return session;
} catch (error) {
await session.abortTransaction();
throw error;
}
}
}
4. Lock Monitoring ve Performance
4.1 Lock Monitoring
class LockMonitor {
constructor() {
this.activeLocks = new Map();
}
trackLock(resourceId, lockType, session) {
this.activeLocks.set(resourceId, {
type: lockType,
acquiredAt: new Date(),
session: session
});
}
releaseLock(resourceId) {
this.activeLocks.delete(resourceId);
}
async getLockStats() {
const currentLocks = await db.currentOp({
$or: [
{ 'waitingForLock': true },
{ 'lockStats': { $exists: true } }
]
});
return {
activeLocks: this.activeLocks.size,
waitingOperations: currentLocks.inprog.filter(
op => op.waitingForLock
).length
};
}
}
4.2 Lock Timeout Yönetimi
class LockTimeoutManager {
static async executeWithTimeout(operation, timeoutMs = 5000) {
const session = client.startSession();
try {
session.startTransaction({
maxTimeMS: timeoutMs
});
const result = await operation(session);
await session.commitTransaction();
return result;
} catch (error) {
if (error.code === 50) {
throw new Error('Lock acquisition timeout');
}
await session.abortTransaction();
throw error;
} finally {
await session.endSession();
}
}
}
5. Best Practices
class LockingBestPractices {
// Lock süresini minimize et
static async minimizeLockDuration(operation) {
// Hazırlık işlemlerini lock dışında yap
const preparedData = await this.prepareData();
const session = client.startSession();
try {
session.startTransaction();
// Minimum sürede lock tut
await operation(session, preparedData);
await session.commitTransaction();
} finally {
await session.endSession();
}
}
// Lock granülaritesini optimize et
static async optimizeLockGranularity(documents) {
const batch = documents.length > 1000 ? 1000 : documents.length;
for (let i = 0; i < documents.length; i += batch) {
const currentBatch = documents.slice(i, i + batch);
await this.processWithLock(currentBatch);
}
}
}
MongoDB’nin locking mekanizmaları, veritabanı operasyonlarının güvenli ve tutarlı bir şekilde gerçekleştirilmesini sağlar. Doğru lock stratejisinin seçimi ve yönetimi, uygulamanın performansı ve ölçeklenebilirliği açısından kritik öneme sahiptir. Lock’ların doğru kullanımı, deadlock’ların önlenmesi ve lock sürelerinin optimize edilmesi, başarılı bir MongoDB uygulaması için temel gereksinimlerdir.
Security
Authentication mekanizmaları
MongoDB Authentication Mekanizmaları
Kimlik Doğrulama Yöntemleri
MongoDB, birkaç farklı kimlik doğrulama mekanizması sunar:
a) SCRAM (Salted Challenge Response Authentication Mechanism):
- Varsayılan ve önerilen kimlik doğrulama mekanizmasıdır
- SCRAM-SHA-1 ve SCRAM-SHA-256 olmak üzere iki versiyonu vardır
- Şifreleri güvenli bir şekilde saklar ve iletir
Örnek SCRAM kullanıcı oluşturma:
use admin
db.createUser(
{
user: "adminUser",
pwd: "güçlüŞifre123",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
b) X.509 Sertifika Kimlik Doğrulaması:
- SSL/TLS sertifikaları kullanarak kimlik doğrulama sağlar
- Özellikle kurumsal ortamlarda tercih edilir
- İstemci ve sunucu arasında güvenli iletişim sağlar
X.509 sertifika ile bağlantı örneği:
mongo --ssl --sslPEMKeyFile client.pem --sslCAFile ca.pem --host mongodb.example.com
Rol Tabanlı Erişim Kontrolü (RBAC)
MongoDB, detaylı yetkilendirme için rol tabanlı erişim kontrolü sunar:
a) Yerleşik Roller:
- read: Sadece okuma yetkisi
- readWrite: Okuma ve yazma yetkisi
- dbAdmin: Veritabanı yönetim yetkisi
- userAdmin: Kullanıcı yönetim yetkisi
- clusterAdmin: Cluster yönetim yetkisi
Örnek rol atama:
db.grantRolesToUser(
"uygulamaKullanici",
[ { role: "readWrite", db: "urunlerDB" } ]
)
b) Özel Roller Oluşturma:
db.createRole(
{
role: "ozelRaporlamaRolu",
privileges: [
{
resource: { db: "satis", collection: "siparisler" },
actions: [ "find" ]
}
],
roles: []
}
)
Güvenlik En İyi Uygulamaları
a) Authentication Zorunlu Kılma:
- mongod.conf dosyasında security.authorization’ı active yapın
security:
authorization: enabled
b) Şifre Politikaları:
- Güçlü şifreler kullanın
- Düzenli şifre değişimi yapın
- Şifre karmaşıklık kuralları belirleyin
c) SSL/TLS Şifreleme:
mongod --sslMode requireSSL --sslPEMKeyFile server.pem
Kullanıcı Yönetimi Komutları
a) Kullanıcı Listeleme:
db.getUsers()
b) Kullanıcı Güncelleme:
db.updateUser(
"mevcutKullanici",
{
pwd: "yeniŞifre",
roles: [ { role: "readWrite", db: "yeniDB" } ]
}
)
c) Kullanıcı Silme:
db.dropUser("silinecekKullanici")
Denetim (Audit)
MongoDB Enterprise sürümünde denetim özelliği bulunur:
mongod --auditDestination file --auditFormat JSON --auditPath /var/log/mongodb/audit.json
Bu, aşağıdaki olayları kaydeder:
- Kimlik doğrulama başarı/başarısızlıkları
- Yetkilendirme işlemleri
- Schema değişiklikleri
- CRUD operasyonları
Güvenlik Kontrol Listesi
- Authentication her zaman aktif olmalı
- En az ayrıcalık prensibini uygulayın
- Düzenli güvenlik denetimi yapın
- Güncel MongoDB sürümünü kullanın
- Firewall kurallarını yapılandırın
- Düzenli yedekleme yapın
- Şifreleme kullanın (hem iletişimde hem depolamada)
Ağ Güvenliği
a) IP Whitelisting:
net:
bindIp: 127.0.0.1,192.168.1.7
b) Port Yapılandırması:
net:
port: 27017
Bu bilgiler MongoDB’de güvenlik ve kimlik doğrulama mekanizmalarının temel yapıtaşlarını oluşturur. Her ortam için özel gereksinimler göz önünde bulundurularak bu mekanizmalar uyarlanmalı ve yapılandırılmalıdır.
Role-Based Access Control (RBAC)
RBAC, kullanıcılara belirli roller atayarak veritabanı kaynaklarına erişimi kontrol eden bir güvenlik mekanizmasıdır. Bu sistem şu bileşenlerden oluşur:
a) Privilege (Ayrıcalık):
- Belirli bir kaynağa yapılabilecek spesifik eylemleri tanımlar
- Resource (kaynak) ve Action (eylem) olmak üzere iki ana bileşenden oluşur
b) Role (Rol):
- Bir veya birden fazla privilege içerebilir
- Diğer rolleri inherit edebilir
- Database seviyesinde veya cluster seviyesinde tanımlanabilir
2. Yerleşik Roller (Built-in Roles)
MongoDB’nin sağladığı hazır roller:
Database User Roles:
// Read rolü atama
db.grantRolesToUser(
"okuyucuKullanici",
[ { role: "read", db: "pazarlama" } ]
)
// ReadWrite rolü atama
db.grantRolesToUser(
"editorKullanici",
[ { role: "readWrite", db: "pazarlama" } ]
)
Database Administration Roles:
// dbAdmin rolü atama
db.grantRolesToUser(
"dbYoneticisi",
[ { role: "dbAdmin", db: "pazarlama" } ]
)
// userAdmin rolü atama
db.grantRolesToUser(
"kullaniciYoneticisi",
[ { role: "userAdmin", db: "pazarlama" } ]
)
Cluster Administration Roles:
// clusterAdmin rolü atama
db.grantRolesToUser(
"clusterYoneticisi",
[ { role: "clusterAdmin", db: "admin" } ]
)
3. Özel Rol Oluşturma
Özel ihtiyaçlar için custom rol oluşturma:
db.createRole(
{
role: "raporlamaRolu",
privileges: [
{
resource: { db: "satis", collection: "siparisler" },
actions: [ "find", "aggregate" ]
},
{
resource: { db: "satis", collection: "musteriler" },
actions: [ "find" ]
}
],
roles: [
{ role: "read", db: "raporlama" }
]
}
)
4. Rol Yönetimi Komutları
a) Rol Bilgisi Görüntüleme:
// Tüm rolleri listele
db.getRoles()
// Spesifik rol detayları
db.getRole("raporlamaRolu",
{ showPrivileges: true, showBuiltinRoles: true })
b) Rol Güncelleme:
db.updateRole(
"raporlamaRolu",
{
privileges: [
{
resource: { db: "satis", collection: "siparisler" },
actions: [ "find", "aggregate", "insert" ]
}
],
roles: [
{ role: "readWrite", db: "raporlama" }
]
}
)
c) Rol Silme:
db.dropRole("raporlamaRolu")
5. İleri Düzey RBAC Özellikleri
a) Collection Seviyesinde Yetkilendirme:
db.createRole(
{
role: "satisTemsilcisiRolu",
privileges: [
{
resource: { db: "satis", collection: "aktifSiparisler" },
actions: [ "find", "insert", "update" ]
},
{
resource: { db: "satis", collection: "tamamlananSiparisler" },
actions: [ "find" ]
}
],
roles: []
}
)
b) Rol Inheritance (Rol Kalıtımı):
db.createRole(
{
role: "seniorSatisTemsilcisiRolu",
privileges: [
{
resource: { db: "satis", collection: "hedefler" },
actions: [ "find", "update" ]
}
],
roles: [
{ role: "satisTemsilcisiRolu", db: "satis" }
]
}
)
6. RBAC Best Practices (En İyi Uygulamalar)
En Az Ayrıcalık Prensibi:
- Kullanıcılara sadece ihtiyaç duydukları minimum yetkileri verin
- Rolleri düzenli olarak gözden geçirin
Rol Hiyerarşisi:
// Temel rol
db.createRole({
role: "baseEmployeeRole",
privileges: [ ... ],
roles: []
})
// Orta seviye rol
db.createRole({
role: "middleManagerRole",
privileges: [ ... ],
roles: [ { role: "baseEmployeeRole", db: "admin" } ]
})
// Üst seviye rol
db.createRole({
role: "seniorManagerRole",
privileges: [ ... ],
roles: [ { role: "middleManagerRole", db: "admin" } ]
})
Rol Denetimi ve İzleme:
// Rol kullanım analizi
db.system.profile.find(
{
"authInfo.authenticatedUsers": {
$exists: true
}
}
)
7. Güvenlik Kontrol ve Denetim
a) Rol Atamalarını Düzenli Kontrol:
// Tüm kullanıcıları ve rollerini listele
db.system.users.find({}, {user: 1, roles: 1})
b) Yetki Denetimi:
// Kullanıcının yetkilerini kontrol et
db.runCommand(
{
usersInfo: "kullaniciAdi",
showPrivileges: true
}
)
Bu bilgiler MongoDB’de RBAC’ın temel yapıtaşlarını oluşturur. Her organizasyon kendi ihtiyaçlarına göre bu yapıyı özelleştirmeli ve düzenli olarak gözden geçirmelidir. RBAC’ın doğru implementasyonu, veritabanı güvenliğinin sağlanmasında kritik bir rol oynar.
Field-Level Encryption
Field-Level Encryption, hassas verilerin uygulama seviyesinde şifrelenmesini sağlayan bir güvenlik özelliğidir. Bu özellik, verilerin client-side şifrelenmesini sağlayarak veritabanı yöneticileri dahil yetkisiz erişimlere karşı koruma sağlar.
Temel Özellikler:
- İstemci tarafında şifreleme
- Otomatik şifreleme/şifre çözme
- Arama yapılabilir şifreleme
- Birden fazla şifreleme anahtarı desteği
2. Şifreleme Yapılandırması
a) Data Encryption Key (DEK) Oluşturma:
// DEK oluşturma
const clientEncryption = new ClientEncryption(client, {
keyVaultNamespace: "encryption.__keyVault",
kmsProviders: {
local: {
key: localMasterKey
}
}
});
const dataKeyId = await clientEncryption.createDataKey('local', {
keyAltNames: ['örnek-veri-anahtari']
});
b) Şifreleme Şeması Tanımlama:
const schema = {
bsonType: "object",
encryptMetadata: {
keyId: [dataKeyId]
},
properties: {
kimlikNo: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic"
}
},
krediKartNo: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Random"
}
}
}
}
3. Şifreleme Türleri
a) Deterministik Şifreleme:
- Aynı değerler için aynı şifreli metin üretir
- Eşitlik sorguları yapılabilir
- Örnek kullanım:
const müşteriKoleksiyonu = client.db("banka").collection("müşteriler", {
schema: {
kimlikNo: {
encrypt: {
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic"
}
}
}
});
// Şifreli alanda arama yapma
await müşteriKoleksiyonu.find({ kimlikNo: "12345678901" });
b) Rastgele Şifreleme:
- Her şifreleme için farklı şifreli metin üretir
- Daha yüksek güvenlik sağlar
- Eşitlik sorguları yapılamaz
const ödemelerKoleksiyonu = client.db("banka").collection("ödemeler", {
schema: {
krediKartNo: {
encrypt: {
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Random"
}
}
}
});
4. Anahtar Yönetimi
a) Key Management Service (KMS) Yapılandırması:
const kmsProviders = {
aws: {
accessKeyId: 'AWS_ACCESS_KEY_ID',
secretAccessKey: 'AWS_SECRET_ACCESS_KEY'
},
local: {
key: Buffer.from('localMasterKey', 'base64')
}
};
const encryption = new ClientEncryption(client, {
keyVaultNamespace: "encryption.__keyVault",
kmsProviders: kmsProviders
});
b) Anahtar Rotasyonu:
// Yeni anahtar oluşturma
const yeniAnahtarId = await encryption.createDataKey('local');
// Eski anahtarla şifrelenmiş verileri yeni anahtarla yeniden şifreleme
await collection.updateMany(
{ "şifreliAlan": { $exists: true } },
[{
$set: {
"şifreliAlan": {
$encrypt: {
keyId: yeniAnahtarId,
value: "$şifreliAlan",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic"
}
}
}
}]
);
5. Uygulama Örnekleri
a) Müşteri Bilgileri Şifreleme:
const müşteriŞeması = {
bsonType: "object",
properties: {
ad: { bsonType: "string" },
soyad: { bsonType: "string" },
tcKimlik: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic"
}
},
telefonNo: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Random"
}
}
}
};
// Müşteri ekleme
await müşteriKoleksiyonu.insertOne({
ad: "Ahmet",
soyad: "Yılmaz",
tcKimlik: "12345678901",
telefonNo: "5551234567"
});
b) Ödeme Bilgileri Şifreleme:
const ödemeŞeması = {
bsonType: "object",
properties: {
kartNo: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Random"
}
},
sonKullanmaTarihi: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Random"
}
},
cvv: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512_Random"
}
}
}
};
6. Best Practices ve Güvenlik Önerileri
Anahtar Yönetimi:
- Anahtarları güvenli bir şekilde saklayın
- Düzenli anahtar rotasyonu yapın
- Yedek anahtarlar oluşturun
Şifreleme Algoritması Seçimi:
- Deterministik şifrelemeyi sadece gerektiğinde kullanın
- Mümkün olduğunca rastgele şifrelemeyi tercih edin
Performance Optimizasyonu:
- Sadece gerekli alanları şifreleyin
- İndeks gerektiren alanlarda deterministik şifreleme kullanın
Hata Yönetimi:
try {
await collection.insertOne({
hassasVeri: "gizli-bilgi"
});
} catch (e) {
if (e.code === 'EncryptionError') {
// Şifreleme hatası yönetimi
console.error('Şifreleme hatası:', e);
}
}
7. İzleme ve Denetim
// Şifreleme işlemlerini izleme
const commandStarted = (event) => {
if (event.command.encrypt) {
console.log('Şifreleme işlemi başladı:', event);
}
};
client.on('commandStarted', commandStarted);
Field-Level Encryption, MongoDB’de hassas verilerin güvenliğini sağlamak için güçlü bir mekanizma sunar. Doğru yapılandırma ve best practice’lerin uygulanması, veri güvenliğinin sağlanmasında kritik öneme sahiptir.
SSL/TLS konfigürasyonu
1. SSL/TLS Nedir ve Neden Önemlidir?
SSL (Secure Sockets Layer) ve TLS (Transport Layer Security), ağ üzerinden iletilen verileri şifrelemek için kullanılan protokollerdir. Bu protokoller, verilerin gizliliğini, bütünlüğünü ve kimlik doğrulamasını sağlar. MongoDB’de SSL/TLS kullanmak, özellikle hassas verilerin iletilmesi gereken durumlarda (örneğin, bulut ortamlarında veya farklı ağlar arasında) büyük önem taşır.
2. MongoDB’de SSL/TLS Konfigürasyonu
MongoDB’de SSL/TLS konfigürasyonu, hem sunucu tarafında hem de istemci tarafında yapılabilir. Bu konfigürasyon, MongoDB’nin SSL/TLS sertifikalarını kullanarak iletişimi şifrelemesini sağlar.
2.1. Sertifikaların Hazırlanması
SSL/TLS kullanabilmek için öncelikle sertifikaların hazırlanması gerekir. Bu sertifikalar genellikle bir Sertifika Otoritesi (CA) tarafından imzalanır. Aşağıdaki adımlarla kendi kendine imzalı sertifikalar oluşturabilirsiniz:
# CA sertifikası oluşturma
openssl req -x509 -newkey rsa:4096 -days 365 -keyout ca-key.pem -out ca-cert.pem -nodes
# Sunucu için private key ve CSR (Certificate Signing Request) oluşturma
openssl req -newkey rsa:4096 -keyout server-key.pem -out server-req.pem -nodes
# CSR'yi CA ile imzalayarak sunucu sertifikasını oluşturma
openssl x509 -req -in server-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365
# İstemci için private key ve CSR oluşturma
openssl req -newkey rsa:4096 -keyout client-key.pem -out client-req.pem -nodes
# CSR'yi CA ile imzalayarak istemci sertifikasını oluşturma
openssl x509 -req -in client-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365
2.2. MongoDB Sunucusunda SSL/TLS Konfigürasyonu
MongoDB sunucusunda SSL/TLS’yi etkinleştirmek için mongod.conf
dosyasında aşağıdaki ayarları yapmanız gerekir:
net:
ssl:
mode: requireSSL
PEMKeyFile: /path/to/server-cert.pem
CAFile: /path/to/ca-cert.pem
allowConnectionsWithoutCertificates: true
- mode:
requireSSL
modu, MongoDB’nin yalnızca SSL/TLS bağlantılarını kabul etmesini sağlar. - PEMKeyFile: Sunucunun sertifika ve private key dosyasının yolu.
- CAFile: CA sertifikasının yolu.
- allowConnectionsWithoutCertificates: İstemcilerin sertifika sunmadan bağlanmasına izin verir.
2.3. MongoDB İstemcisinde SSL/TLS Konfigürasyonu
MongoDB istemcisi (örneğin, mongo
shell veya bir uygulama) sunucuya SSL/TLS üzerinden bağlanmak için aşağıdaki gibi konfigüre edilebilir:
mongo --ssl --sslCAFile /path/to/ca-cert.pem --sslPEMKeyFile /path/to/client-cert.pem --host <mongodb-host>
- –ssl: SSL/TLS kullanarak bağlanmayı etkinleştirir.
- –sslCAFile: CA sertifikasının yolu.
- –sslPEMKeyFile: İstemcinin sertifika ve private key dosyasının yolu.
2.4. Uygulama Tarafında SSL/TLS Konfigürasyonu
Eğer bir uygulama üzerinden MongoDB’ye bağlanıyorsanız, kullandığınız MongoDB sürücüsüne göre SSL/TLS konfigürasyonu yapmanız gerekir. Örneğin, Node.js için mongoose
kütüphanesi kullanıyorsanız:
const mongoose = require('mongoose');
const fs = require('fs');
const ca = [fs.readFileSync("/path/to/ca-cert.pem")];
const cert = fs.readFileSync("/path/to/client-cert.pem");
const key = fs.readFileSync("/path/to/client-key.pem");
mongoose.connect('mongodb://<mongodb-host>:27017/mydatabase', {
ssl: true,
sslValidate: true,
sslCA: ca,
sslCert: cert,
sslKey: key,
sslPass: 'your-passphrase-if-any'
});
3. Güvenlik Önerileri
- Sertifika Yönetimi: Sertifikaların güvenli bir şekilde saklandığından ve düzenli olarak güncellendiğinden emin olun.
- Sertifika İptali: İptal edilmiş sertifikaların kullanımını engellemek için CRL (Certificate Revocation List) veya OCSP (Online Certificate Status Protocol) kullanın.
- Güçlü Şifreleme Algoritmaları: Güçlü şifreleme algoritmaları ve anahtar uzunlukları kullanın (örneğin, RSA 4096 bit veya ECDSA).
- Sertifika Doğrulaması: İstemci tarafında sunucu sertifikasını doğrulayarak “man-in-the-middle” saldırılarını önleyin.
4. Sık Karşılaşılan Sorunlar ve Çözümleri
- Sertifika Doğrulama Hatası: Eğer sertifikalar doğru şekilde yapılandırılmamışsa, MongoDB bağlantıları başarısız olabilir. Bu durumda, sertifikaların doğru yollarda olduğundan ve CA sertifikasının doğru olduğundan emin olun.
- Zaman Uyumsuzluğu: Sertifikaların geçerlilik süresi dolmuşsa veya sistem saatleri senkronize değilse bağlantı sorunları yaşanabilir. Sistem saatlerinin doğru olduğundan emin olun.
Audit logging
1. Audit Logging Nedir ve Neden Önemlidir?
Audit Logging, MongoDB’de gerçekleştirilen belirli işlemlerin (örneğin, kimlik doğrulama, yetkilendirme, veri erişimi, yönetimsel işlemler) kaydedilmesi sürecidir. Bu kayıtlar, aşağıdaki durumlar için kritik öneme sahiptir:
- Güvenlik İhlallerini Tespit Etme: Yetkisiz erişim veya şüpheli aktivitelerin tespit edilmesine yardımcı olur.
- Uyumluluk Gereksinimleri: HIPAA, GDPR, PCI-DSS gibi düzenlemeler, denetim kayıtlarının tutulmasını zorunlu kılar.
- Operasyonel Analiz: Veritabanı üzerindeki işlemlerin izlenmesi ve analiz edilmesi için kullanılır.
2. MongoDB’de Audit Logging Nasıl Çalışır?
MongoDB, denetim kayıtlarını belirli olay türlerine (event types) göre kaydeder. Örneğin:
- Kimlik Doğrulama (Authentication): Kullanıcı girişleri ve çıkışları.
- Yetkilendirme (Authorization): Kullanıcıların yetkilerini aşma girişimleri.
- Veri Erişimi (CRUD İşlemleri): Veritabanı üzerinde gerçekleştirilen sorgular, eklemeler, güncellemeler ve silmeler.
- Yönetimsel İşlemler: Veritabanı yapılandırması, kullanıcı yönetimi gibi işlemler.
Denetim kayıtları, JSON formatında tutulur ve belirli bir dosyaya, syslog’a veya bir MongoDB koleksiyonuna yazılabilir.
3. MongoDB’de Audit Logging Konfigürasyonu
MongoDB’de denetim kaydını etkinleştirmek için aşağıdaki adımları izleyebilirsiniz.
3.1. MongoDB Yapılandırma Dosyası (mongod.conf
)
Denetim kaydını etkinleştirmek için mongod.conf
dosyasında aşağıdaki ayarları yapın:
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/auditLog.json
- destination: Denetim kayıtlarının nereye yazılacağını belirtir.
file
,syslog
veyaconsole
olabilir. - format: Kayıtların formatını belirtir.
JSON
veyaBSON
olabilir. - path: Kayıtların yazılacağı dosya yolu (yalnızca
destination: file
için geçerlidir).
3.2. Denetim Filtreleri (Audit Filters)
Denetim kayıtlarını belirli olay türlerine göre filtrelemek için audit filters kullanabilirsiniz. Örneğin, yalnızca kimlik doğrulama ve yetkilendirme olaylarını kaydetmek için:
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/auditLog.json
filter: '{ atype: { $in: ["authenticate", "authCheck"] } }'
- filter: JSON formatında bir sorgu belirtir. Bu sorgu, hangi olay türlerinin kaydedileceğini belirler.
3.3. MongoDB’yi Yeniden Başlatma
Yapılandırma dosyasını güncelledikten sonra MongoDB’yi yeniden başlatın:
sudo systemctl restart mongod
4. Denetim Kayıtlarını İnceleme
Denetim kayıtları, belirttiğiniz dosyaya veya koleksiyona JSON formatında yazılır. Örnek bir denetim kaydı:
{
"atype": "authenticate",
"ts": { "$date": "2023-10-05T12:34:56.789Z" },
"local": { "ip": "127.0.0.1", "port": 27017 },
"remote": { "ip": "192.168.1.100", "port": 54321 },
"users": [{ "user": "admin", "db": "admin" }],
"result": 0
}
- atype: Olay türü (örneğin,
authenticate
,authCheck
,createCollection
). - ts: Olayın zaman damgası.
- local: MongoDB sunucusunun IP ve port bilgisi.
- remote: İstemcinin IP ve port bilgisi.
- users: İşlemi gerçekleştiren kullanıcı bilgisi.
- result: İşlemin sonucu (0 başarılı, diğer değerler hata kodları).
5. Denetim Kayıtlarını MongoDB Koleksiyonuna Yazma
Denetim kayıtlarını bir MongoDB koleksiyonuna yazmak için aşağıdaki yapılandırmayı kullanabilirsiniz:
auditLog:
destination: console
format: JSON
filter: '{ atype: { $in: ["authenticate", "authCheck"] } }'
Ardından, mongod
başlatılırken --auditDestination
parametresini kullanın:
mongod --dbpath /data/db --auditDestination syslog
6. Güvenlik ve Performans İpuçları
- Kayıt Dosyası Boyutu: Denetim kayıtları büyük boyutlara ulaşabilir. Düzenli olarak dosyaları temizleyin veya rotasyon uygulayın.
- Filtreleme: Gereksiz kayıtları önlemek için filtreler kullanın.
- Şifreleme: Denetim kayıtlarını şifreleyerek saklayın.
- Erişim Kontrolü: Denetim kayıtlarına yalnızca yetkili kişilerin erişebilmesini sağlayın.
7. Sık Karşılaşılan Sorunlar ve Çözümleri
- Performans Etkisi: Denetim kaydı, özellikle yüksek trafikli sistemlerde performansı etkileyebilir. Filtreleme kullanarak bu etkiyi azaltabilirsiniz.
- Kayıt Dosyasının Büyümesi: Kayıt dosyalarının düzenli olarak temizlenmesi veya rotasyon uygulanması gerekir.
- Yanlış Filtreleme: Yanlış filtreleme, önemli olayların kaydedilmemesine neden olabilir. Filtreleri dikkatlice yapılandırın.
Back-end Entegrasyonu
MongoDB sürücüleri (Node.js, Python vb.)
1. MongoDB Sürücüleri Nedir ve Neden Önemlidir?
MongoDB sürücüleri, MongoDB veritabanı ile uygulama arasında iletişim kurmak için kullanılan resmi veya topluluk tarafından geliştirilmiş kütüphanelerdir. Bu sürücüler, uygulamanın MongoDB’ye bağlanmasını, sorgular yapmasını, veri eklemesini, güncellemesini ve silmesini sağlar.
Sürücülerin önemi:
- Dil Desteği: Farklı programlama dilleri için uyumlu sürücüler mevcuttur.
- Performans: MongoDB’nin özelliklerini en iyi şekilde kullanarak yüksek performans sağlar.
- Güvenlik: SSL/TLS, kimlik doğrulama gibi güvenlik özelliklerini destekler.
- Esneklik: MongoDB’nin esnek veri modeli ve sorgu yeteneklerini kullanmayı kolaylaştırır.
2. MongoDB Sürücüleri ile Back-End Entegrasyonu
MongoDB sürücüleri, farklı programlama dilleri için farklı şekillerde entegre edilebilir. Aşağıda, popüler diller için MongoDB sürücülerinin nasıl kullanılacağını açıklayacağım.
2.1. Node.js ile MongoDB Entegrasyonu
Node.js için resmi MongoDB sürücüsü MongoDB Node.js Driver‘dır. Bu sürücü, MongoDB ile etkileşim kurmak için kullanılır.
Kurulum:
npm install mongodb
Bağlantı ve Temel İşlemler:
const { MongoClient } = require('mongodb');
// MongoDB bağlantı URL'si
const uri = 'mongodb://localhost:27017';
// MongoDB istemcisi oluşturma
const client = new MongoClient(uri);
async function run() {
try {
// MongoDB'ye bağlanma
await client.connect();
console.log('MongoDB\'ye bağlandı.');
// Veritabanı ve koleksiyon seçme
const database = client.db('mydatabase');
const collection = database.collection('mycollection');
// Veri ekleme
const doc = { name: 'John Doe', age: 30 };
const result = await collection.insertOne(doc);
console.log(`Eklenen belge ID: ${result.insertedId}`);
// Veri sorgulama
const query = { name: 'John Doe' };
const user = await collection.findOne(query);
console.log('Bulunan kullanıcı:', user);
} finally {
// Bağlantıyı kapatma
await client.close();
}
}
run().catch(console.dir);
- MongoClient: MongoDB’ye bağlantı sağlar.
- db(): Veritabanını seçer.
- collection(): Koleksiyonu seçer.
- insertOne(): Tek bir belge ekler.
- findOne(): Tek bir belge sorgular.
2.2. Python ile MongoDB Entegrasyonu
Python için resmi MongoDB sürücüsü PyMongo‘dur.
Kurulum:
pip install pymongo
Bağlantı ve Temel İşlemler:
from pymongo import MongoClient
# MongoDB bağlantı URL'si
uri = "mongodb://localhost:27017"
# MongoDB istemcisi oluşturma
client = MongoClient(uri)
# Veritabanı ve koleksiyon seçme
db = client['mydatabase']
collection = db['mycollection']
# Veri ekleme
doc = {"name": "Jane Doe", "age": 25}
result = collection.insert_one(doc)
print(f"Eklenen belge ID: {result.inserted_id}")
# Veri sorgulama
query = {"name": "Jane Doe"}
user = collection.find_one(query)
print("Bulunan kullanıcı:", user)
# Bağlantıyı kapatma
client.close()
- MongoClient: MongoDB’ye bağlantı sağlar.
- insert_one(): Tek bir belge ekler.
- find_one(): Tek bir belge sorgular.
2.3. Java ile MongoDB Entegrasyonu
Java için resmi MongoDB sürücüsü MongoDB Java Driver‘dır.
Maven Bağımlılığı:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.7.0</version>
</dependency>
Bağlantı ve Temel İşlemler:
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
public class MongoDBExample {
public static void main(String[] args) {
// MongoDB bağlantı URL'si
String uri = "mongodb://localhost:27017";
// MongoDB istemcisi oluşturma
try (MongoClient client = MongoClients.create(uri)) {
// Veritabanı ve koleksiyon seçme
MongoDatabase database = client.getDatabase("mydatabase");
MongoCollection<Document> collection = database.getCollection("mycollection");
// Veri ekleme
Document doc = new Document("name", "Alice").append("age", 28);
collection.insertOne(doc);
System.out.println("Belge eklendi.");
// Veri sorgulama
Document query = new Document("name", "Alice");
Document user = collection.find(query).first();
System.out.println("Bulunan kullanıcı: " + user.toJson());
}
}
}
- MongoClients.create(): MongoDB’ye bağlantı sağlar.
- getDatabase(): Veritabanını seçer.
- getCollection(): Koleksiyonu seçer.
- insertOne(): Tek bir belge ekler.
- find(): Belge sorgular.
3. Sürücülerin Ortak Özellikleri
- Bağlantı Yönetimi: MongoDB’ye bağlantı kurma ve yönetme.
- CRUD İşlemleri: Veri ekleme, sorgulama, güncelleme ve silme.
- İndeks Yönetimi: İndeks oluşturma ve yönetme.
- Topluluk Desteği: Geniş bir topluluk tarafından desteklenir.
4. Güvenlik ve Performans İpuçları
- Bağlantı Havuzu: Bağlantı havuzu kullanarak performansı artırın.
- SSL/TLS: Veri iletişimini şifrelemek için SSL/TLS kullanın.
- Kimlik Doğrulama: MongoDB’ye bağlanırken kullanıcı adı ve şifre kullanın.
- Sürücü Güncellemeleri: Sürücüleri düzenli olarak güncelleyin.
Mongoose ODM kullanımı
1. Mongoose Nedir ve Neden Kullanılır?
Mongoose, MongoDB için bir ODM kütüphanesidir. MongoDB’nin belge tabanlı yapısını, şema (schema) ve model (model) kavramlarıyla daha yapılandırılmış hale getirir. Mongoose’un avantajları şunlardır:
- Şema Tanımlama: Verilerin yapısını şemalarla tanımlayabilirsiniz.
- Doğrulama (Validation): Veri ekleme ve güncelleme sırasında otomatik doğrulama yapar.
- Middleware (Ara Yazılım): Veri işlemleri sırasında özel işlevler ekleyebilirsiniz.
- İlişkisel Veri Yönetimi: Belge ilişkilerini kolayca yönetebilirsiniz.
- Sorgu Oluşturma: MongoDB sorgularını daha okunabilir ve yönetilebilir hale getirir.
2. Mongoose Kurulumu ve Temel Kullanım
Mongoose’u kullanmak için öncelikle Node.js projenize kurmanız gerekir.
2.1. Kurulum:
npm install mongoose
2.2. MongoDB’ye Bağlanma:
Mongoose ile MongoDB’ye bağlanmak için aşağıdaki kodu kullanabilirsiniz:
const mongoose = require('mongoose');
// MongoDB bağlantı URL'si
const uri = 'mongodb://localhost:27017/mydatabase';
// MongoDB'ye bağlanma
mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB\'ye bağlandı.'))
.catch(err => console.error('Bağlantı hatası:', err));
- useNewUrlParser: MongoDB bağlantı URL’sini modern bir şekilde ayrıştırır.
- useUnifiedTopology: MongoDB sunucusuyla daha kararlı bir bağlantı sağlar.
3. Şema ve Model Oluşturma
Mongoose’da verilerin yapısını şema (schema) ile tanımlar ve bu şemayı kullanarak model (model) oluşturursunuz.
3.1. Şema Tanımlama:
const mongoose = require('mongoose');
// Kullanıcı şeması
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true, // Zorunlu alan
},
age: {
type: Number,
min: 18, // Minimum değer
max: 100, // Maksimum değer
},
email: {
type: String,
required: true,
unique: true, // Benzersiz olmalı
},
createdAt: {
type: Date,
default: Date.now, // Varsayılan değer
},
});
- type: Alanın veri türünü belirtir (String, Number, Date, vb.).
- required: Alanın zorunlu olup olmadığını belirtir.
- unique: Alanın benzersiz olmasını sağlar.
- default: Alanın varsayılan değerini belirtir.
3.2. Model Oluşturma:
Şemayı kullanarak bir model oluşturun:
const User = mongoose.model('User', userSchema);
- mongoose.model(): Şemayı kullanarak bir model oluşturur. İlk parametre modelin adı, ikinci parametre şemadır.
4. Temel CRUD İşlemleri
Mongoose ile MongoDB üzerinde temel CRUD (Create, Read, Update, Delete) işlemlerini gerçekleştirebilirsiniz.
4.1. Veri Ekleme (Create):
const newUser = new User({
name: 'John Doe',
age: 30,
email: 'john@example.com',
});
newUser.save()
.then(doc => console.log('Kullanıcı eklendi:', doc))
.catch(err => console.error('Hata:', err));
- save(): Belgeyi veritabanına kaydeder.
4.2. Veri Sorgulama (Read):
// Tüm kullanıcıları getirme
User.find()
.then(users => console.log('Tüm kullanıcılar:', users))
.catch(err => console.error('Hata:', err));
// Belirli bir kullanıcıyı getirme
User.findOne({ name: 'John Doe' })
.then(user => console.log('Bulunan kullanıcı:', user))
.catch(err => console.error('Hata:', err));
- find(): Tüm belgeleri getirir.
- findOne(): Belirli bir belgeyi getirir.
4.3. Veri Güncelleme (Update):
User.updateOne({ name: 'John Doe' }, { age: 31 })
.then(result => console.log('Güncelleme sonucu:', result))
.catch(err => console.error('Hata:', err));
- updateOne(): Belirli bir belgeyi günceller.
4.4. Veri Silme (Delete):
User.deleteOne({ name: 'John Doe' })
.then(result => console.log('Silme sonucu:', result))
.catch(err => console.error('Hata:', err));
- deleteOne(): Belirli bir belgeyi siler.
5. Middleware (Ara Yazılım) Kullanımı
Mongoose, veri işlemleri sırasında çalıştırılabilen middleware fonksiyonlarını destekler. Örneğin, bir belge kaydedilmeden önce veya sonra özel işlemler yapabilirsiniz.
5.1. Pre Middleware:
userSchema.pre('save', function (next) {
console.log('Belge kaydediliyor:', this);
next(); // İşlemi devam ettir
});
- pre(): Belirli bir işlemden önce çalıştırılır.
5.2. Post Middleware:
userSchema.post('save', function (doc, next) {
console.log('Belge kaydedildi:', doc);
next();
});
- post(): Belirli bir işlemden sonra çalıştırılır.
6. İlişkisel Veri Yönetimi
Mongoose, belgeler arasında ilişki kurmayı kolaylaştırır. Örneğin, bir kullanıcının birden fazla görevi olabilir.
6.1. Referans ile İlişki Kurma:
const taskSchema = new mongoose.Schema({
description: String,
completed: Boolean,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User', // User modeline referans
},
});
const Task = mongoose.model('Task', taskSchema);
- ref: Başka bir modeli referans alır.
6.2. İlişkili Veri Ekleme:
const user = new User({ name: 'Jane Doe', email: 'jane@example.com' });
user.save()
.then(user => {
const task = new Task({ description: 'Learn Mongoose', completed: false, user: user._id });
return task.save();
})
.then(task => console.log('Görev eklendi:', task))
.catch(err => console.error('Hata:', err));
Connection pooling
1. Connection Pooling Nedir ve Neden Önemlidir?
Connection Pooling, veritabanı bağlantılarının önceden oluşturulup bir havuzda tutulması ve bu bağlantıların gerektiğinde yeniden kullanılmasıdır. Her bir bağlantı, MongoDB sunucusuna yapılan bir TCP bağlantısını temsil eder.
Neden Önemlidir?
- Performans: Her istekte yeni bir bağlantı oluşturmak yerine, havuzdaki mevcut bağlantılar kullanılarak performans artırılır.
- Kaynak Tasarrufu: Bağlantıların yeniden kullanılması, sunucu kaynaklarını daha verimli kullanır.
- Ölçeklenebilirlik: Yüksek eşzamanlı isteklerde bağlantı havuzu, uygulamanın daha iyi ölçeklenmesini sağlar.
- Bağlantı Yönetimi: Bağlantıların yaşam döngüsü daha iyi yönetilir (örneğin, bağlantıların zaman aşımına uğraması veya kapatılması).
2. MongoDB’de Connection Pooling Nasıl Çalışır?
MongoDB sürücüleri (Node.js, Python, Java, vb.), bağlantı havuzu desteği sunar. Bu sürücüler, bağlantı havuzunu otomatik olarak yönetir ve uygulamanın ihtiyaçlarına göre bağlantıları ayarlar.
Bağlantı Havuzu Parametreleri:
- maxPoolSize: Havuzda tutulacak maksimum bağlantı sayısı.
- minPoolSize: Havuzda tutulacak minimum bağlantı sayısı.
- maxIdleTimeMS: Kullanılmayan bağlantıların havuzda kalabileceği maksimum süre (milisaniye cinsinden).
- waitQueueTimeoutMS: Bağlantı talebinin havuzda bekleyeceği maksimum süre (milisaniye cinsinden).
3. Node.js ile MongoDB Connection Pooling
Node.js’de MongoDB sürücüsü veya Mongoose kullanarak bağlantı havuzunu yapılandırabilirsiniz.
3.1. MongoDB Node.js Driver ile Connection Pooling:
const { MongoClient } = require('mongodb');
// MongoDB bağlantı URL'si
const uri = 'mongodb://localhost:27017';
// Bağlantı havuzu ayarları
const options = {
maxPoolSize: 10, // Maksimum bağlantı sayısı
minPoolSize: 2, // Minimum bağlantı sayısı
maxIdleTimeMS: 30000, // 30 saniye
waitQueueTimeoutMS: 5000, // 5 saniye
};
// MongoDB istemcisi oluşturma
const client = new MongoClient(uri, options);
async function run() {
try {
// MongoDB'ye bağlanma
await client.connect();
console.log('MongoDB\'ye bağlandı.');
// Veritabanı ve koleksiyon seçme
const database = client.db('mydatabase');
const collection = database.collection('mycollection');
// Veri sorgulama
const query = { name: 'John Doe' };
const user = await collection.findOne(query);
console.log('Bulunan kullanıcı:', user);
} finally {
// Bağlantıyı kapatma (isteğe bağlı, havuz otomatik yönetir)
await client.close();
}
}
run().catch(console.dir);
- maxPoolSize: Havuzda en fazla 10 bağlantı tutulur.
- minPoolSize: Havuzda en az 2 bağlantı tutulur.
- maxIdleTimeMS: 30 saniye boyunca kullanılmayan bağlantılar kapatılır.
- waitQueueTimeoutMS: Bağlantı talebi 5 saniyeden uzun sürerse hata verir.
3.2. Mongoose ile Connection Pooling:
Mongoose, MongoDB Node.js Driver’ın üzerine inşa edilmiştir ve bağlantı havuzunu otomatik olarak yönetir.
const mongoose = require('mongoose');
// MongoDB bağlantı URL'si
const uri = 'mongodb://localhost:27017/mydatabase';
// Bağlantı havuzu ayarları
const options = {
maxPoolSize: 10, // Maksimum bağlantı sayısı
minPoolSize: 2, // Minimum bağlantı sayısı
serverSelectionTimeoutMS: 5000, // Sunucu seçimi için maksimum bekleme süresi
};
// MongoDB'ye bağlanma
mongoose.connect(uri, options)
.then(() => console.log('MongoDB\'ye bağlandı.'))
.catch(err => console.error('Bağlantı hatası:', err));
- maxPoolSize: Havuzda en fazla 10 bağlantı tutulur.
- minPoolSize: Havuzda en az 2 bağlantı tutulur.
- serverSelectionTimeoutMS: Sunucu seçimi için 5 saniye bekler.
4. Python ile MongoDB Connection Pooling
Python’da PyMongo kütüphanesi ile bağlantı havuzunu yapılandırabilirsiniz.
4.1. PyMongo ile Connection Pooling:
from pymongo import MongoClient
# MongoDB bağlantı URL'si
uri = "mongodb://localhost:27017"
# Bağlantı havuzu ayarları
client = MongoClient(uri, maxPoolSize=10, minPoolSize=2, maxIdleTimeMS=30000)
# Veritabanı ve koleksiyon seçme
db = client['mydatabase']
collection = db['mycollection']
# Veri sorgulama
query = {"name": "John Doe"}
user = collection.find_one(query)
print("Bulunan kullanıcı:", user)
# Bağlantıyı kapatma (isteğe bağlı, havuz otomatik yönetir)
client.close()
- maxPoolSize: Havuzda en fazla 10 bağlantı tutulur.
- minPoolSize: Havuzda en az 2 bağlantı tutulur.
- maxIdleTimeMS: 30 saniye boyunca kullanılmayan bağlantılar kapatılır.
5. Java ile MongoDB Connection Pooling
Java’da MongoDB Java Driver ile bağlantı havuzunu yapılandırabilirsiniz.
5.1. MongoDB Java Driver ile Connection Pooling:
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
public class MongoDBExample {
public static void main(String[] args) {
// MongoDB bağlantı URL'si
String uri = "mongodb://localhost:27017";
// Bağlantı havuzu ayarları
MongoClient client = MongoClients.create(uri + "/?maxPoolSize=10&minPoolSize=2&maxIdleTimeMS=30000");
// Veritabanı ve koleksiyon seçme
MongoDatabase database = client.getDatabase("mydatabase");
MongoCollection<Document> collection = database.getCollection("mycollection");
// Veri sorgulama
Document query = new Document("name", "John Doe");
Document user = collection.find(query).first();
System.out.println("Bulunan kullanıcı: " + user.toJson());
// Bağlantıyı kapatma (isteğe bağlı, havuz otomatik yönetir)
client.close();
}
}
- maxPoolSize: Havuzda en fazla 10 bağlantı tutulur.
- minPoolSize: Havuzda en az 2 bağlantı tutulur.
- maxIdleTimeMS: 30 saniye boyunca kullanılmayan bağlantılar kapatılır.
6. Bağlantı Havuzu Yönetimi İpuçları
- Doğru Havuz Boyutu: Uygulamanın ihtiyaçlarına göre
maxPoolSize
veminPoolSize
değerlerini ayarlayın. - Zaman Aşımı:
maxIdleTimeMS
vewaitQueueTimeoutMS
gibi parametrelerle bağlantıların yaşam döngüsünü yönetin. - İzleme ve Analiz: Bağlantı havuzu performansını izleyin ve gerektiğinde ayarlamalar yapın.
Error handling
1. Error Handling Nedir ve Neden Önemlidir?
Error Handling, uygulama sırasında ortaya çıkabilecek hataları tespit etme, bu hatalara uygun şekilde tepki verme ve uygulamanın kararlılığını koruma sürecidir. MongoDB ile çalışırken hata yönetimi özellikle önemlidir çünkü:
- Veri Kaybını Önler: Hataların doğru şekilde ele alınması, veri kaybını önler.
- Uygulama Kararlılığı: Hataların uygun şekilde yönetilmesi, uygulamanın çökmesini engeller.
- Kullanıcı Deneyimi: Kullanıcılara anlamlı hata mesajları sunarak deneyimi iyileştirir.
- Güvenlik: Hataların güvenlik açıklarına yol açmasını engeller.
2. MongoDB’de Sık Karşılaşılan Hatalar
MongoDB ile çalışırken karşılaşılabilecek bazı yaygın hatalar şunlardır:
- Bağlantı Hataları: MongoDB sunucusuna bağlanılamaması.
- Sorgu Hataları: Geçersiz sorgular veya veri bulunamaması.
- Doğrulama Hataları: Şema doğrulama kurallarının ihlal edilmesi.
- Yetkilendirme Hataları: Kullanıcının gerekli izinlere sahip olmaması.
- Zaman Aşımı Hataları: Sorguların belirli bir sürede tamamlanamaması.
3. Node.js ile MongoDB’de Error Handling
Node.js’de MongoDB sürücüsü veya Mongoose kullanarak hata yönetimini nasıl yapabileceğinizi inceleyelim.
3.1. MongoDB Node.js Driver ile Error Handling:
const { MongoClient } = require('mongodb');
// MongoDB bağlantı URL'si
const uri = 'mongodb://localhost:27017';
async function run() {
const client = new MongoClient(uri);
try {
// MongoDB'ye bağlanma
await client.connect();
console.log('MongoDB\'ye bağlandı.');
// Veritabanı ve koleksiyon seçme
const database = client.db('mydatabase');
const collection = database.collection('mycollection');
// Geçersiz sorgu örneği
const query = { name: 'John Doe' };
const user = await collection.findOne(query);
if (!user) {
throw new Error('Kullanıcı bulunamadı.');
}
console.log('Bulunan kullanıcı:', user);
} catch (error) {
// Hata yakalama
console.error('Hata oluştu:', error.message);
} finally {
// Bağlantıyı kapatma
await client.close();
}
}
run();
- try-catch: Hataları yakalamak için kullanılır.
- throw: Özel hata mesajları oluşturmak için kullanılır.
- finally: Bağlantıyı kapatmak gibi temizlik işlemleri için kullanılır.
3.2. Mongoose ile Error Handling:
Mongoose, hata yönetimi için daha gelişmiş özellikler sunar.
const mongoose = require('mongoose');
// MongoDB bağlantı URL'si
const uri = 'mongodb://localhost:27017/mydatabase';
// Kullanıcı şeması
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
age: { type: Number, min: 18 },
});
// Kullanıcı modeli
const User = mongoose.model('User', userSchema);
async function run() {
try {
// MongoDB'ye bağlanma
await mongoose.connect(uri);
console.log('MongoDB\'ye bağlandı.');
// Geçersiz veri örneği
const newUser = new User({ age: 15 }); // name alanı eksik ve age minimum değerin altında
await newUser.save();
} catch (error) {
// Mongoose ValidationError kontrolü
if (error.name === 'ValidationError') {
console.error('Doğrulama hatası:', error.message);
} else {
console.error('Hata oluştu:', error.message);
}
} finally {
// Bağlantıyı kapatma
await mongoose.connection.close();
}
}
run();
- ValidationError: Mongoose’un şema doğrulama hatalarını yakalar.
- error.name: Hata türünü belirlemek için kullanılır.
4. Python ile MongoDB’de Error Handling
Python’da PyMongo kütüphanesi ile hata yönetimi yapabilirsiniz.
4.1. PyMongo ile Error Handling:
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure, OperationFailure
# MongoDB bağlantı URL'si
uri = "mongodb://localhost:27017"
try:
# MongoDB'ye bağlanma
client = MongoClient(uri)
print("MongoDB'ye bağlandı.")
# Veritabanı ve koleksiyon seçme
db = client['mydatabase']
collection = db['mycollection']
# Geçersiz sorgu örneği
query = {"name": "John Doe"}
user = collection.find_one(query)
if not user:
raise Exception("Kullanıcı bulunamadı.")
print("Bulunan kullanıcı:", user)
except ConnectionFailure as e:
print("Bağlantı hatası:", str(e))
except OperationFailure as e:
print("Operasyon hatası:", str(e))
except Exception as e:
print("Hata oluştu:", str(e))
finally:
# Bağlantıyı kapatma
client.close()
- ConnectionFailure: MongoDB’ye bağlantı hatası.
- OperationFailure: Sorgu veya operasyon hatası.
- Exception: Genel hatalar için.
5. Java ile MongoDB’de Error Handling
Java’da MongoDB Java Driver ile hata yönetimi yapabilirsiniz.
5.1. MongoDB Java Driver ile Error Handling:
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.MongoException;
import org.bson.Document;
public class MongoDBExample {
public static void main(String[] args) {
// MongoDB bağlantı URL'si
String uri = "mongodb://localhost:27017";
try (MongoClient client = MongoClients.create(uri)) {
// Veritabanı ve koleksiyon seçme
MongoDatabase database = client.getDatabase("mydatabase");
MongoCollection<Document> collection = database.getCollection("mycollection");
// Geçersiz sorgu örneği
Document query = new Document("name", "John Doe");
Document user = collection.find(query).first();
if (user == null) {
throw new Exception("Kullanıcı bulunamadı.");
}
System.out.println("Bulunan kullanıcı: " + user.toJson());
} catch (MongoException e) {
System.err.println("MongoDB hatası: " + e.getMessage());
} catch (Exception e) {
System.err.println("Hata oluştu: " + e.getMessage());
}
}
}
- MongoException: MongoDB’ye özgü hatalar.
- Exception: Genel hatalar için.
6. Hata Yönetimi İpuçları
- Özel Hata Sınıfları: Uygulamanıza özel hata sınıfları oluşturun.
- Loglama: Hataları loglayarak izleme ve analiz yapın.
- Kullanıcı Dostu Mesajlar: Kullanıcılara anlamlı hata mesajları sunun.
- Test: Hata senaryolarını test ederek uygulamanın kararlılığını sağlayın.
Retry mekanizmaları
1. Retry Mekanizmaları Nedir ve Neden Önemlidir?
Retry Mekanizmaları, bir işlem başarısız olduğunda, belirli bir stratejiye göre işlemi otomatik olarak yeniden deneyen yapılardır. Bu mekanizmalar özellikle şu durumlarda önemlidir:
- Geçici Hatalar: Ağ kesintileri, sunucu yükü gibi geçici sorunlarla başa çıkmak.
- Uygulama Kararlılığı: Hataların uygulamanın çökmesine neden olmasını engellemek.
- Kullanıcı Deneyimi: Kullanıcıların hatalarla karşılaşma olasılığını azaltmak.
- Veri Bütünlüğü: Veri kaybını önlemek ve işlemlerin tamamlanmasını sağlamak.
2. Retry Mekanizmalarının Temel Bileşenleri
Bir retry mekanizması genellikle aşağıdaki bileşenleri içerir:
- Retry Sayısı (Retry Count): İşlemin kaç kez yeniden denenebileceği.
- Retry Aralığı (Retry Interval): Yeniden denemeler arasındaki bekleme süresi.
- Backoff Stratejisi: Yeniden denemeler arasındaki bekleme süresinin artırılması (örneğin, üstel artış).
- Koşullar (Conditions): Hangi hataların yeniden denenebileceği (örneğin, ağ hataları).
3. Node.js ile MongoDB’de Retry Mekanizmaları
Node.js’de MongoDB sürücüsü veya Mongoose kullanarak retry mekanizmalarını nasıl uygulayabileceğinizi inceleyelim.
3.1. MongoDB Node.js Driver ile Retry Mekanizması:
MongoDB Node.js Driver, otomatik retry özellikleri sunar. Ayrıca, özel bir retry mekanizması da uygulanabilir.
const { MongoClient } = require('mongodb');
// MongoDB bağlantı URL'si
const uri = 'mongodb://localhost:27017';
// Retry mekanizması
async function withRetry(operation, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
return await operation();
} catch (error) {
if (i === retries - 1) throw error; // Son denemede hata fırlat
console.log(`Hata oluştu, yeniden deniyor (${i + 1}/${retries})...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
async function run() {
const client = new MongoClient(uri);
try {
// MongoDB'ye bağlanma
await withRetry(async () => {
await client.connect();
console.log('MongoDB\'ye bağlandı.');
});
// Veritabanı ve koleksiyon seçme
const database = client.db('mydatabase');
const collection = database.collection('mycollection');
// Veri sorgulama
const query = { name: 'John Doe' };
const user = await collection.findOne(query);
console.log('Bulunan kullanıcı:', user);
} catch (error) {
console.error('Hata oluştu:', error.message);
} finally {
// Bağlantıyı kapatma
await client.close();
}
}
run();
- withRetry: Özel bir retry mekanizması.
- retries: Yeniden deneme sayısı.
- delay: Yeniden denemeler arasındaki bekleme süresi.
3.2. Mongoose ile Retry Mekanizması:
Mongoose, otomatik olarak bağlantı hatalarında retry yapar. Ayrıca, özel bir retry mekanizması da uygulanabilir.
const mongoose = require('mongoose');
// MongoDB bağlantı URL'si
const uri = 'mongodb://localhost:27017/mydatabase';
// Retry mekanizması
async function connectWithRetry() {
const retries = 3;
const delay = 1000;
for (let i = 0; i < retries; i++) {
try {
await mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });
console.log('MongoDB\'ye bağlandı.');
return;
} catch (error) {
if (i === retries - 1) throw error; // Son denemede hata fırlat
console.log(`Bağlantı hatası, yeniden deniyor (${i + 1}/${retries})...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
async function run() {
try {
await connectWithRetry();
// Kullanıcı modeli
const User = mongoose.model('User', new mongoose.Schema({ name: String }));
// Veri sorgulama
const user = await User.findOne({ name: 'John Doe' });
console.log('Bulunan kullanıcı:', user);
} catch (error) {
console.error('Hata oluştu:', error.message);
} finally {
// Bağlantıyı kapatma
await mongoose.connection.close();
}
}
run();
- connectWithRetry: Bağlantı için özel bir retry mekanizması.
4. Python ile MongoDB’de Retry Mekanizmaları
Python’da PyMongo kütüphanesi ile retry mekanizmalarını uygulayabilirsiniz.
4.1. PyMongo ile Retry Mekanizması:
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure
import time
# MongoDB bağlantı URL'si
uri = "mongodb://localhost:27017"
# Retry mekanizması
def with_retry(operation, retries=3, delay=1):
for i in range(retries):
try:
return operation()
except ConnectionFailure as e:
if i == retries - 1:
raise e # Son denemede hata fırlat
print(f"Hata oluştu, yeniden deniyor ({i + 1}/{retries})...")
time.sleep(delay)
def run():
try:
# MongoDB'ye bağlanma
client = with_retry(lambda: MongoClient(uri))
print("MongoDB'ye bağlandı.")
# Veritabanı ve koleksiyon seçme
db = client['mydatabase']
collection = db['mycollection']
# Veri sorgulama
query = {"name": "John Doe"}
user = collection.find_one(query)
print("Bulunan kullanıcı:", user)
except Exception as e:
print("Hata oluştu:", str(e))
finally:
# Bağlantıyı kapatma
client.close()
run()
- with_retry: Özel bir retry mekanizması.
- retries: Yeniden deneme sayısı.
- delay: Yeniden denemeler arasındaki bekleme süresi.
5. Java ile MongoDB’de Retry Mekanizmaları
Java’da MongoDB Java Driver ile retry mekanizmalarını uygulayabilirsiniz.
5.1. MongoDB Java Driver ile Retry Mekanizması:
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.MongoException;
import org.bson.Document;
public class MongoDBExample {
public static void main(String[] args) {
// MongoDB bağlantı URL'si
String uri = "mongodb://localhost:27017";
// Retry mekanizması
MongoClient client = connectWithRetry(uri, 3, 1000);
try {
// Veritabanı ve koleksiyon seçme
MongoDatabase database = client.getDatabase("mydatabase");
MongoCollection<Document> collection = database.getCollection("mycollection");
// Veri sorgulama
Document query = new Document("name", "John Doe");
Document user = collection.find(query).first();
System.out.println("Bulunan kullanıcı: " + user.toJson());
} catch (MongoException e) {
System.err.println("Hata oluştu: " + e.getMessage());
} finally {
// Bağlantıyı kapatma
client.close();
}
}
private static MongoClient connectWithRetry(String uri, int retries, long delay) {
for (int i = 0; i < retries; i++) {
try {
return MongoClients.create(uri);
} catch (MongoException e) {
if (i == retries - 1) throw e; // Son denemede hata fırlat
System.out.println("Bağlantı hatası, yeniden deniyor (" + (i + 1) + "/" + retries + ")...");
try {
Thread.sleep(delay);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
return null;
}
}
- connectWithRetry: Bağlantı için özel bir retry mekanizması.
- retries: Yeniden deneme sayısı.
- delay: Yeniden denemeler arasındaki bekleme süresi.
6. Retry Mekanizmaları İpuçları
- Üstel Artış (Exponential Backoff): Yeniden denemeler arasındaki bekleme süresini artırarak sunucu yükünü azaltın.
- Koşullu Retry: Yalnızca geçici hatalarda (örneğin, ağ hataları) retry yapın.
- Loglama: Retry işlemlerini loglayarak izleme ve analiz yapın.
Deployment ve Operations
Replication kavramı
1. Replication Nedir ve Neden Önemlidir?
Replication, verilerin birden fazla sunucu üzerinde kopyalanması ve senkronize edilmesi sürecidir. MongoDB’de replication, bir Replica Set (Çoğaltma Kümesi) ile sağlanır. Bir Replica Set, aynı veri kümesini tutan birden fazla MongoDB örneğinden (instance) oluşur.
Neden Önemlidir?
- Yüksek Kullanılabilirlik: Bir sunucu arızalandığında, diğer sunucular hizmet vermeye devam eder.
- Veri Güvenliği: Veriler birden fazla sunucuda kopyalandığı için veri kaybı riski azalır.
- Ölçeklenebilirlik: Okuma işlemleri birden fazla sunucuya dağıtılarak performans artırılır.
- Otomatik Failover: Birincil sunucu arızalandığında, otomatik olarak yeni bir birincil sunucu seçilir.
2. Replica Set Yapısı
Bir Replica Set, genellikle aşağıdaki bileşenlerden oluşur:
- Primary (Birincil): Tüm yazma işlemlerini gerçekleştiren ve verileri diğer sunuculara çoğaltan ana sunucu.
- Secondary (İkincil): Birincil sunucudan verileri kopyalayan ve okuma işlemlerini gerçekleştirebilen sunucular.
- Arbiter (Hakem): Oylamaya katılan ancak veri tutmayan özel bir sunucu. Yalnızca failover sürecinde kullanılır.
3. Replica Set Kurulumu
MongoDB’de bir Replica Set oluşturmak için aşağıdaki adımları izleyebilirsiniz.
3.1. MongoDB Örneklerini Başlatma:
Her bir MongoDB örneği farklı portlarda çalışacak şekilde başlatılır.
# Birincil sunucu
mongod --replSet myReplicaSet --port 27017 --dbpath /data/db1
# İkincil sunucu 1
mongod --replSet myReplicaSet --port 27018 --dbpath /data/db2
# İkincil sunucu 2
mongod --replSet myReplicaSet --port 27019 --dbpath /data/db3
- –replSet: Replica Set adını belirtir.
- –port: MongoDB örneğinin çalışacağı port.
- –dbpath: Veritabanı dosyalarının saklanacağı dizin.
3.2. Replica Set’i Yapılandırma:
Birincil sunucuya bağlanarak Replica Set’i yapılandırın.
mongo --port 27017
MongoDB shell’de aşağıdaki komutları çalıştırın:
rs.initiate({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
});
- rs.initiate(): Replica Set’i başlatır ve üyeleri tanımlar.
- _id: Replica Set adı.
- members: Replica Set üyeleri.
3.3. Replica Set Durumunu Kontrol Etme:
Replica Set durumunu kontrol etmek için aşağıdaki komutu kullanın:
rs.status();
Bu komut, Replica Set’in durumu, üyeleri ve rolleri hakkında bilgi verir.
4. Replica Set İşlemleri
4.1. Veri Yazma ve Çoğaltma:
Birincil sunucuya veri yazıldığında, bu veri otomatik olarak ikincil sunuculara çoğaltılır.
// Birincil sunucuya bağlanma
mongo --port 27017
// Veritabanı ve koleksiyon seçme
use myDatabase;
db.myCollection.insert({ name: "John Doe", age: 30 });
4.2. Okuma İşlemlerini İkincil Sunuculara Yönlendirme:
Varsayılan olarak, okuma işlemleri birincil sunucuya yönlendirilir. İkincil sunuculardan okuma yapmak için aşağıdaki komutu kullanın:
db.myCollection.find().readPref("secondary");
- readPref(“secondary”): Okuma işlemlerini ikincil sunuculara yönlendirir.
4.3. Failover Senaryosu:
Birincil sunucu arızalandığında, Replica Set otomatik olarak yeni bir birincil sunucu seçer. Bu süreç failover olarak adlandırılır.
5. Replica Set Yönetimi
5.1. Üye Ekleme ve Çıkarma:
Replica Set’e yeni üyeler eklemek veya mevcut üyeleri çıkarmak için aşağıdaki komutları kullanabilirsiniz.
// Yeni üye ekleme
rs.add("localhost:27020");
// Üye çıkarma
rs.remove("localhost:27020");
5.2. Arbiter Ekleme:
Arbiter, yalnızca oylamaya katılan ve veri tutmayan bir üyedir. Arbiter eklemek için:
rs.addArb("localhost:27021");
5.3. Replica Set Ayarlarını Güncelleme:
Replica Set ayarlarını güncellemek için aşağıdaki komutu kullanın:
rs.reconfig({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019", priority: 0 } // Bu üye birincil olamaz
]
});
- priority: Üyenin birincil olma önceliği.
0
değeri, üyenin birincil olamayacağını belirtir.
6. Replica Set ve Uygulama Entegrasyonu
Uygulamalar, MongoDB sürücüleri aracılığıyla Replica Set’e bağlanabilir. Örneğin, Node.js’de:
const { MongoClient } = require('mongodb');
// Replica Set bağlantı URL'si
const uri = 'mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=myReplicaSet';
async function run() {
const client = new MongoClient(uri);
try {
await client.connect();
console.log('Replica Set\'e bağlandı.');
const database = client.db('myDatabase');
const collection = database.collection('myCollection');
// Veri ekleme
await collection.insertOne({ name: 'Jane Doe', age: 25 });
console.log('Veri eklendi.');
// Veri sorgulama
const user = await collection.findOne({ name: 'Jane Doe' });
console.log('Bulunan kullanıcı:', user);
} finally {
await client.close();
}
}
run().catch(console.dir);
- replicaSet: Replica Set adını belirtir.
Sharding stratejileri
1. Sharding Nedir ve Neden Önemlidir?
Sharding, veritabanındaki büyük veri kümelerini birden fazla sunucuya (shard) dağıtarak yönetme işlemidir. Her bir shard, veritabanının bir alt kümesini tutar ve sorgular bu shard’lar arasında dağıtılır.
Neden Önemlidir?
- Ölçeklenebilirlik: Veri ve iş yükü birden fazla sunucuya dağıtılarak sistemin ölçeklenebilirliği artırılır.
- Performans: Sorgular ve işlemler birden fazla shard üzerinde paralel olarak çalıştırılabilir.
- Depolama Kapasitesi: Tek bir sunucunun depolama sınırlamaları aşılır.
- Yük Dengeleme: Veri ve iş yükü shard’lar arasında dengelenir.
2. Sharding Bileşenleri
MongoDB’de sharding, aşağıdaki bileşenlerden oluşur:
- Shard: Verilerin saklandığı her bir MongoDB örneği. Her shard, bir Replica Set olabilir.
- Config Server: Sharding metadata’sını (hangi verinin hangi shard’da olduğu gibi) tutan özel MongoDB örnekleri.
- Mongos (Query Router): Uygulamaların shard’lara erişmesini sağlayan yönlendirici. Sorguları ilgili shard’lara yönlendirir.
3. Sharding Stratejileri
MongoDB’de sharding, shard key (parçalama anahtarı) adı verilen bir alana göre yapılır. Shard key, verilerin shard’lar arasında nasıl dağıtılacağını belirler. Temel sharding stratejileri şunlardır:
3.1. Range-Based Sharding (Aralık Temelli Parçalama):
Veriler, shard key’in değer aralıklarına göre shard’lara dağıtılır. Örneğin, age
alanına göre sharding yapıldığını varsayalım:
- Shard 1:
age
0-30 - Shard 2:
age
31-60 - Shard 3:
age
61-100
Avantajları:
- Aralık sorguları (range queries) için etkilidir.
- Veri dağılımı anlaşılabilir.
Dezavantajları:
- Shard key’in dağılımı dengesiz olabilir (örneğin, çoğu veri belirli bir aralıkta toplanabilir).
3.2. Hash-Based Sharding (Hash Temelli Parçalama):
Veriler, shard key’in hash değerine göre shard’lara dağıtılır. Bu yöntem, verilerin daha dengeli bir şekilde dağıtılmasını sağlar.
Avantajları:
- Veri dağılımı daha dengelidir.
- Shard key’in dağılımı önemli değildir.
Dezavantajları:
- Aralık sorguları (range queries) için uygun değildir.
3.3. Zoned Sharding (Bölge Temelli Parçalama):
Veriler, belirli bölgelere (zones) göre shard’lara dağıtılır. Bu yöntem, coğrafi veya mantıksal gruplamalar için kullanılır.
Avantajları:
- Coğrafi veya mantıksal gruplamalar için idealdir.
- Veri yerelliği (data locality) sağlar.
Dezavantajları:
- Karmaşık yapılandırma gerektirir.
4. Sharding Kurulumu
MongoDB’de sharding yapılandırmak için aşağıdaki adımları izleyebilirsiniz.
4.1. Config Server’ları Başlatma:
Config server’lar, sharding metadata’sını tutar. En az 3 config server önerilir.
mongod --configsvr --replSet configReplSet --port 27019 --dbpath /data/configdb1
mongod --configsvr --replSet configReplSet --port 27020 --dbpath /data/configdb2
mongod --configsvr --replSet configReplSet --port 27021 --dbpath /data/configdb3
Config Replica Set’i başlatın:
mongo --port 27019
rs.initiate({
_id: "configReplSet",
configsvr: true,
members: [
{ _id: 0, host: "localhost:27019" },
{ _id: 1, host: "localhost:27020" },
{ _id: 2, host: "localhost:27021" }
]
});
4.2. Mongos’u Başlatma:
Mongos, sorguları shard’lara yönlendirir.
mongos --configdb configReplSet/localhost:27019,localhost:27020,localhost:27021 --port 27017
4.3. Shard’ları Başlatma ve Eklemek:
Her bir shard, bir MongoDB örneği veya Replica Set olabilir.
mongod --shardsvr --replSet shardReplSet1 --port 27022 --dbpath /data/shard1
mongod --shardsvr --replSet shardReplSet2 --port 27023 --dbpath /data/shard2
Shard Replica Set’lerini başlatın:
mongo --port 27022
rs.initiate({
_id: "shardReplSet1",
members: [
{ _id: 0, host: "localhost:27022" }
]
});
mongo --port 27023
rs.initiate({
_id: "shardReplSet2",
members: [
{ _id: 0, host: "localhost:27023" }
]
});
Shard’ları mongos’a ekleyin:
mongo --port 27017
sh.addShard("shardReplSet1/localhost:27022");
sh.addShard("shardReplSet2/localhost:27023");
4.4. Veritabanı ve Koleksiyon için Sharding Etkinleştirme:
Sharding’i etkinleştirmek için:
sh.enableSharding("myDatabase");
sh.shardCollection("myDatabase.myCollection", { shardKey: 1 });
- shardKey: Sharding için kullanılacak alan.
5. Sharding Yönetimi
5.1. Shard Durumunu Kontrol Etme:
Shard’ların durumunu kontrol etmek için:
sh.status();
5.2. Shard Ekleme ve Çıkarma:
Yeni shard eklemek veya mevcut shard’ı çıkarmak için:
sh.addShard("shardReplSet3/localhost:27024");
sh.removeShard("shardReplSet1/localhost:27022");
5.3. Shard Key Değiştirme:
Shard key değiştirmek için önce koleksiyonu yeniden oluşturmanız gerekir.
6. Sharding ve Uygulama Entegrasyonu
Uygulamalar, mongos üzerinden shard’lara erişir. Örneğin, Node.js’de:
const { MongoClient } = require('mongodb');
// Mongos bağlantı URL'si
const uri = 'mongodb://localhost:27017';
async function run() {
const client = new MongoClient(uri);
try {
await client.connect();
console.log('Mongos\'a bağlandı.');
const database = client.db('myDatabase');
const collection = database.collection('myCollection');
// Veri ekleme
await collection.insertOne({ shardKey: 'value1', name: 'John Doe' });
console.log('Veri eklendi.');
// Veri sorgulama
const user = await collection.findOne({ shardKey: 'value1' });
console.log('Bulunan kullanıcı:', user);
} finally {
await client.close();
}
}
run().catch(console.dir);
Backup ve restore işlemleri
1. Backup ve Restore Nedir ve Neden Önemlidir?
Backup, veritabanındaki verilerin bir kopyasını alarak güvenli bir şekilde saklama işlemidir. Restore ise bu yedekten verileri geri yükleme işlemidir.
Neden Önemlidir?
- Veri Kaybını Önleme: Donanım arızaları, yazılım hataları veya insan hataları nedeniyle veri kaybını önler.
- Felaket Kurtarma: Doğal afetler, siber saldırılar gibi durumlarda verilerin geri yüklenmesini sağlar.
- Uyumluluk: Yasal düzenlemeler ve kurumsal politikalar gereği yedekleme yapmak zorunlu olabilir.
- Veri Taşıma: Verileri farklı bir ortama taşımak için yedekleme ve geri yükleme kullanılır.
2. MongoDB’de Backup ve Restore Yöntemleri
MongoDB’de yedekleme ve geri yükleme için temel yöntemler şunlardır:
MongoDB Araçları ile Yedekleme ve Geri Yükleme:
- mongodump: Veritabanını yedekler.
- mongorestore: Yedekten verileri geri yükler.
Dosya Sisteminin Yedeğini Alma:
- Veritabanı dosyalarının (
data/db
) doğrudan kopyasını almak.
Bulut Yedekleme Çözümleri:
- MongoDB Atlas gibi bulut tabanlı çözümlerle otomatik yedekleme.
3. MongoDB Araçları ile Yedekleme ve Geri Yükleme
3.1. mongodump ile Yedekleme:
mongodump
, veritabanındaki verileri BSON formatında yedekler.
mongodump --host localhost --port 27017 --db myDatabase --out /backup/mongodb
- –host: MongoDB sunucusunun adresi.
- –port: MongoDB sunucusunun portu.
- –db: Yedeklenecek veritabanı adı.
- –out: Yedeklerin kaydedileceği dizin.
3.2. mongorestore ile Geri Yükleme:
mongorestore
, mongodump
ile alınan yedekleri geri yükler.
mongorestore --host localhost --port 27017 --db myDatabase /backup/mongodb/myDatabase
- –db: Geri yüklenecek veritabanı adı.
- /backup/mongodb/myDatabase: Yedeklerin bulunduğu dizin.
4. Dosya Sisteminin Yedeğini Alma
MongoDB, verileri data/db
dizininde saklar. Bu dizinin doğrudan kopyasını alarak yedekleme yapabilirsiniz.
4.1. Yedekleme:
MongoDB örneğini durdurun ve data/db
dizinini kopyalayın.
sudo systemctl stop mongod
cp -r /data/db /backup/mongodb
sudo systemctl start mongod
4.2. Geri Yükleme:
MongoDB örneğini durdurun ve yedeklenen dizini geri yükleyin.
sudo systemctl stop mongod
cp -r /backup/mongodb /data/db
sudo systemctl start mongod
5. Bulut Yedekleme Çözümleri
MongoDB Atlas, otomatik yedekleme ve geri yükleme özellikleri sunar. Atlas, verilerinizi düzenli aralıklarla yedekler ve bu yedeklerden kolayca geri yükleme yapabilirsiniz.
5.1. Otomatik Yedekleme:
Atlas, her 6 saatte bir otomatik yedekleme yapar. Ayrıca, manuel yedekleme de yapabilirsiniz.
5.2. Geri Yükleme:
Atlas arayüzünden bir yedeği seçerek geri yükleme işlemi başlatabilirsiniz.
6. Yedekleme ve Geri Yükleme İpuçları
- Düzenli Yedekleme: Veri kaybını önlemek için düzenli aralıklarla yedekleme yapın.
- Yedekleri Doğrulama: Yedeklerin doğru şekilde alındığını ve geri yüklenebilir olduğunu kontrol edin.
- Güvenli Saklama: Yedekleri güvenli bir yerde saklayın (örneğin, şifrelenmiş depolama).
- Test Geri Yükleme: Yedeklerin geri yüklenebilir olduğunu düzenli olarak test edin.
7. Örnek Senaryolar
7.1. Tüm Veritabanını Yedekleme ve Geri Yükleme:
# Yedekleme
mongodump --host localhost --port 27017 --out /backup/mongodb
# Geri Yükleme
mongorestore --host localhost --port 27017 /backup/mongodb
7.2. Belirli Bir Koleksiyonu Yedekleme ve Geri Yükleme:
# Yedekleme
mongodump --host localhost --port 27017 --db myDatabase --collection myCollection --out /backup/mongodb
# Geri Yükleme
mongorestore --host localhost --port 27017 --db myDatabase --collection myCollection /backup/mongodb/myDatabase/myCollection.bson
7.3. Sıkıştırılmış Yedekleme:
# Yedekleme
mongodump --host localhost --port 27017 --gzip --out /backup/mongodb
# Geri Yükleme
mongorestore --host localhost --port 27017 --gzip /backup/mongodb
Monitoring ve logging
1. Monitoring ve Logging Nedir ve Neden Önemlidir?
Monitoring, MongoDB örneklerinin performansını, kaynak kullanımını ve sağlığını gerçek zamanlı olarak izleme sürecidir. Logging ise MongoDB’nin ürettiği logları (kayıtları) toplama, saklama ve analiz etme işlemidir.
Neden Önemlidir?
- Performans Optimizasyonu: Yavaş sorguları, kaynak tüketimini ve diğer performans sorunlarını tespit eder.
- Hata Tespiti: Sistem hatalarını ve anormallikleri hızlıca tespit eder.
- Güvenlik: Şüpheli aktiviteleri ve yetkisiz erişimleri izler.
- Kapasite Planlaması: Kaynak kullanımını analiz ederek gelecekteki ihtiyaçları planlar.
2. MongoDB’de Monitoring
MongoDB, performans ve sağlık izleme için çeşitli araçlar ve metrikler sunar.
2.1. MongoDB Cloud Manager ve Ops Manager:
Bulut tabanlı veya şirket içi çözümlerle MongoDB örneklerini izleyebilirsiniz. Bu araçlar, performans metriklerini, replikasyon durumunu, sharding durumunu ve daha fazlasını izler.
2.2. MongoDB Atlas:
MongoDB’nin bulut tabanlı hizmeti olan Atlas, otomatik izleme ve uyarı özellikleri sunar.
2.3. MongoDB Shell ve Komutlar:
MongoDB shell üzerinden çeşitli komutlarla performans metriklerini izleyebilirsiniz.
// Sunucu durumunu kontrol etme
db.serverStatus()
// Veritabanı istatistiklerini görüntüleme
db.stats()
// Koleksiyon istatistiklerini görüntüleme
db.myCollection.stats()
// Aktif işlemleri görüntüleme
db.currentOp()
// Yavaş sorguları görüntüleme
db.myCollection.find().explain("executionStats")
3. MongoDB’de Logging
MongoDB, sistem olaylarını, hataları ve performans bilgilerini loglar. Bu loglar, sorun giderme ve analiz için kritik öneme sahiptir.
3.1. Log Seviyeleri:
MongoDB, farklı log seviyeleri sunar:
- 0: Kapalı (Loglama yok)
- 1: Hata (Error)
- 2: Uyarı (Warning)
- 3: Bilgi (Informational)
- 4: Hata Ayıklama (Debug)
- 5: Ayrıntılı (Verbose)
3.2. Log Yapılandırması:
Log seviyelerini ve log dosyası konumunu mongod.conf
dosyasında yapılandırabilirsiniz.
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
verbosity: 2
- destination: Logların nereye yazılacağını belirtir (
file
veyasyslog
). - path: Log dosyasının yolu.
- logAppend: Yeni logların mevcut dosyaya eklenip eklenmeyeceğini belirtir.
- verbosity: Log seviyesi.
3.3. Logları Görüntüleme:
Log dosyalarını doğrudan okuyabilir veya tail
gibi araçlarla gerçek zamanlı olarak izleyebilirsiniz.
tail -f /var/log/mongodb/mongod.log
4. Üçüncü Taraf Araçlarla Monitoring ve Logging
MongoDB, üçüncü taraf izleme ve loglama araçlarıyla entegre olabilir.
4.1. Prometheus ve Grafana:
Prometheus, MongoDB metriklerini toplamak için kullanılır. Grafana ise bu metrikleri görselleştirir.
- MongoDB Prometheus Exporter: MongoDB metriklerini Prometheus’a aktarır.
- Grafana Panoları: MongoDB metriklerini görselleştirir.
4.2. ELK Stack (Elasticsearch, Logstash, Kibana):
ELK Stack, MongoDB loglarını toplamak, işlemek ve görselleştirmek için kullanılır.
- Logstash: MongoDB loglarını toplar ve Elasticsearch’e gönderir.
- Elasticsearch: Logları indeksler ve saklar.
- Kibana: Logları görselleştirir.
4.3. Datadog ve New Relic:
Bu araçlar, MongoDB’nin performans metriklerini ve loglarını izlemek için kullanılır.
5. Örnek Senaryolar
5.1. MongoDB Loglarını ELK Stack ile İzleme:
- Logstash Yapılandırması:
input {
file {
path => "/var/log/mongodb/mongod.log"
start_position => "beginning"
}
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:loglevel} %{GREEDYDATA:message}" }
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
index => "mongodb-logs-%{+YYYY.MM.dd}"
}
}
- Kibana’da Logları Görselleştirme:
- Kibana’da
mongodb-logs-*
indeksini kullanarak logları görselleştirin.
5.2. MongoDB Metriklerini Prometheus ve Grafana ile İzleme:
- MongoDB Prometheus Exporter Kurulumu:
docker run -d --name mongodb-exporter -p 9216:9216 percona/mongodb_exporter:0.20.0
- Prometheus Yapılandırması:
scrape_configs:
- job_name: 'mongodb'
static_configs:
- targets: ['localhost:9216']
- Grafana Panosu Oluşturma:
- Grafana’da MongoDB metriklerini görselleştirmek için bir pano oluşturun.
6. İzleme ve Loglama İpuçları
- Düzenli İzleme: Performans metriklerini ve logları düzenli olarak izleyin.
- Uyarılar: Kritik metrikler için uyarılar (alert) yapılandırın.
- Log Rotasyonu: Log dosyalarının büyümesini önlemek için log rotasyonu kullanın.
- Güvenlik: Loglara yetkisiz erişimi engelleyin.
Performance tuning
1. Performance Tuning Nedir ve Neden Önemlidir?
Performance Tuning, MongoDB’nin performansını artırmak için yapılan ayarlamalar ve optimizasyonlardır. Bu işlemler, sorgu performansını, kaynak kullanımını ve genel sistem verimliliğini iyileştirir.
Neden Önemlidir?
- Hızlı Yanıt Süreleri: Kullanıcıların daha hızlı yanıt almasını sağlar.
- Kaynak Verimliliği: CPU, bellek ve disk kullanımını optimize eder.
- Ölçeklenebilirlik: Sistemin daha fazla yükü kaldırabilmesini sağlar.
- Maliyet Tasarrufu: Daha az kaynakla daha fazla iş yaparak maliyetleri düşürür.
2. MongoDB’de Performance Tuning Stratejileri
MongoDB’de performans ayarlaması için aşağıdaki stratejileri kullanabilirsiniz:
- İndeksleme (Indexing)
- Sorgu Optimizasyonu
- Sharding ve Replication
- Kaynak Yönetimi
- Donanım Optimizasyonu
- Yapılandırma Ayarları
3. İndeksleme (Indexing)
İndeksler, sorgu performansını önemli ölçüde artırır. Ancak, yanlış kullanıldığında yazma performansını düşürebilir.
3.1. İndeks Türleri:
- Tek Alan İndeksi (Single Field Index): Bir alan üzerinde indeks oluşturur.
- Bileşik İndeks (Compound Index): Birden fazla alan üzerinde indeks oluşturur.
- Çok Anahtarlı İndeks (Multikey Index): Dizi alanları üzerinde indeks oluşturur.
- Metin İndeksi (Text Index): Metin aramaları için indeks oluşturur.
- Coğrafi İndeks (Geospatial Index): Coğrafi sorgular için indeks oluşturur.
3.2. İndeks Oluşturma:
// Tek alan indeksi
db.myCollection.createIndex({ name: 1 });
// Bileşik indeks
db.myCollection.createIndex({ name: 1, age: -1 });
// Metin indeksi
db.myCollection.createIndex({ description: "text" });
- 1: Artan sıralama.
- -1: Azalan sıralama.
3.3. İndeks Analizi:
// Sorgu performansını analiz etme
db.myCollection.find({ name: "John Doe" }).explain("executionStats");
// İndeksleri listeleme
db.myCollection.getIndexes();
4. Sorgu Optimizasyonu
Sorguların performansını artırmak için aşağıdaki ipuçlarını kullanabilirsiniz.
4.1. Sorgu Seçiciliği:
Sorguların mümkün olduğunca seçici olmasını sağlayın. Örneğin, age
gibi yüksek seçiciliğe sahip alanlar kullanın.
4.2. Projeksiyon Kullanımı:
Sadece ihtiyaç duyulan alanları getirin.
db.myCollection.find({ name: "John Doe" }, { name: 1, age: 1 });
4.3. Sorgu Analizi:
Sorguların performansını analiz edin ve yavaş sorguları optimize edin.
db.myCollection.find({ name: "John Doe" }).explain("executionStats");
5. Sharding ve Replication
Sharding ve replication, performansı artırmak ve yüksek kullanılabilirlik sağlamak için kullanılır.
5.1. Sharding:
Büyük veri kümelerini birden fazla sunucuya dağıtarak performansı artırır.
sh.enableSharding("myDatabase");
sh.shardCollection("myDatabase.myCollection", { shardKey: 1 });
5.2. Replication:
Verilerin birden fazla sunucuda kopyalanmasını sağlar ve okuma performansını artırır.
rs.initiate({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
});
6. Kaynak Yönetimi
MongoDB’nin kaynak kullanımını optimize etmek için aşağıdaki adımları izleyebilirsiniz.
6.1. Bellek Yönetimi:
MongoDB, verileri bellek üzerinde tutar. Bellek kullanımını optimize etmek için:
- WiredTiger Cache: WiredTiger depolama motorunun bellek kullanımını ayarlayın.
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 2
6.2. Disk Yönetimi:
Disk performansını artırmak için:
- SSD Kullanımı: SSD’ler, yüksek IOPS (Input/Output Operations Per Second) sağlar.
- Disk Bölümleme: Veritabanı dosyalarını farklı disklerde saklayın.
7. Donanım Optimizasyonu
MongoDB’nin performansını artırmak için donanım kaynaklarını optimize edin.
7.1. CPU:
- Çok Çekirdekli İşlemciler: MongoDB, çok çekirdekli işlemcilerden yararlanır.
- CPU Frekansı: Yüksek frekanslı işlemciler, sorgu performansını artırır.
7.2. Bellek:
- Yeterli RAM: MongoDB, verileri bellek üzerinde tutar. Yeterli RAM, performansı artırır.
7.3. Disk:
- Yüksek IOPS: SSD’ler, yüksek IOPS sağlar.
- RAID Yapılandırması: RAID 10, performans ve güvenilirlik sağlar.
8. Yapılandırma Ayarları
MongoDB’nin performansını artırmak için yapılandırma ayarlarını optimize edin.
8.1. mongod.conf Ayarları:
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 2
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
verbosity: 1
net:
port: 27017
bindIp: 127.0.0.1
8.2. Write Concern:
Yazma işlemlerinin güvenilirliğini artırın.
db.myCollection.insert({ name: "John Doe" }, { writeConcern: { w: "majority" } });
8.3. Read Preference:
Okuma işlemlerini ikincil sunuculara yönlendirin.
db.myCollection.find().readPref("secondary");
9. Örnek Senaryolar
9.1. Yavaş Sorguları Optimize Etme:
// Yavaş sorguyu analiz etme
db.myCollection.find({ age: { $gt: 30 } }).explain("executionStats");
// İndeks oluşturma
db.myCollection.createIndex({ age: 1 });
// Optimize edilmiş sorgu
db.myCollection.find({ age: { $gt: 30 } }).hint({ age: 1 });
9.2. Sharding ile Performans Artırma:
// Sharding'i etkinleştirme
sh.enableSharding("myDatabase");
// Koleksiyonu shard'lara dağıtma
sh.shardCollection("myDatabase.myCollection", { shardKey: 1 });
Scaling stratejileri
1. Scaling Nedir ve Neden Önemlidir?
Scaling, bir sistemin artan iş yüklerini ve veri büyümesini yönetmek için kapasitesini artırma sürecidir. MongoDB’de scaling, Vertical Scaling (Dikey Ölçeklendirme) ve Horizontal Scaling (Yatay Ölçeklendirme) olarak ikiye ayrılır.
Neden Önemlidir?
- Performans: Artan iş yüklerini karşılamak için performansı artırır.
- Kullanılabilirlik: Sistemin kesintisiz çalışmasını sağlar.
- Veri Büyümesi: Büyüyen veri kümelerini yönetmek için depolama kapasitesini artırır.
- Maliyet Optimizasyonu: Kaynakları verimli kullanarak maliyetleri düşürür.
2. Vertical Scaling (Dikey Ölçeklendirme)
Vertical Scaling, mevcut sunucunun kaynaklarını (CPU, bellek, disk) artırarak kapasiteyi artırma işlemidir.
Avantajları:
- Basit Yapılandırma: Yeni sunucular eklemeye gerek yoktur.
- Uyumluluk: Mevcut uygulamalar ve yapılandırmalar değişmez.
Dezavantajları:
- Sınırlı Ölçeklenebilirlik: Tek bir sunucunun kaynakları sınırlıdır.
- Yüksek Maliyet: Yüksek performanslı donanım pahalıdır.
Örnek:
Mevcut bir MongoDB sunucusunun bellek ve CPU’sunu artırmak.
3. Horizontal Scaling (Yatay Ölçeklendirme)
Horizontal Scaling, birden fazla sunucu ekleyerek kapasiteyi artırma işlemidir. MongoDB’de horizontal scaling, Sharding (Parçalama) ile sağlanır.
Avantajları:
- Yüksek Ölçeklenebilirlik: Sınırsız sayıda sunucu eklenebilir.
- Yüksek Kullanılabilirlik: Veriler birden fazla sunucuda kopyalanır.
- Maliyet Etkin: Düşük maliyetli sunucularla ölçeklenebilir.
Dezavantajları:
- Karmaşık Yapılandırma: Sharding yapılandırması ve yönetimi karmaşıktır.
- Ağ Gecikmesi: Shard’lar arası iletişimde gecikme olabilir.
4. Sharding (Parçalama)
Sharding, MongoDB’de horizontal scaling sağlamak için kullanılan bir yöntemdir. Veriler, birden fazla shard (parça) üzerinde dağıtılır.
4.1. Sharding Bileşenleri:
- Shard: Verilerin saklandığı her bir MongoDB örneği.
- Config Server: Sharding metadata’sını tutan özel MongoDB örnekleri.
- Mongos (Query Router): Sorguları ilgili shard’lara yönlendiren yönlendirici.
4.2. Sharding Stratejileri:
- Range-Based Sharding: Veriler, shard key’in değer aralıklarına göre dağıtılır.
- Hash-Based Sharding: Veriler, shard key’in hash değerine göre dağıtılır.
- Zoned Sharding: Veriler, belirli bölgelere (zones) göre dağıtılır.
4.3. Sharding Kurulumu:
- Config Server’ları Başlatma:
mongod --configsvr --replSet configReplSet --port 27019 --dbpath /data/configdb1
mongod --configsvr --replSet configReplSet --port 27020 --dbpath /data/configdb2
mongod --configsvr --replSet configReplSet --port 27021 --dbpath /data/configdb3
- Mongos’u Başlatma:
mongos --configdb configReplSet/localhost:27019,localhost:27020,localhost:27021 --port 27017
- Shard’ları Başlatma ve Eklemek:
mongod --shardsvr --replSet shardReplSet1 --port 27022 --dbpath /data/shard1
mongod --shardsvr --replSet shardReplSet2 --port 27023 --dbpath /data/shard2
- Shard’ları Mongos’a Eklemek:
mongo --port 27017
sh.addShard("shardReplSet1/localhost:27022");
sh.addShard("shardReplSet2/localhost:27023");
- Sharding’i Etkinleştirme:
sh.enableSharding("myDatabase");
sh.shardCollection("myDatabase.myCollection", { shardKey: 1 });
5. Replication (Çoğaltma)
Replication, verilerin birden fazla sunucuda kopyalanmasını sağlar. Bu, yüksek kullanılabilirlik ve okuma performansı sağlar.
5.1. Replica Set Yapısı:
- Primary (Birincil): Tüm yazma işlemlerini gerçekleştirir.
- Secondary (İkincil): Birincil sunucudan verileri kopyalar.
- Arbiter (Hakem): Oylamaya katılan ancak veri tutmayan özel bir sunucu.
5.2. Replica Set Kurulumu:
mongod --replSet myReplicaSet --port 27017 --dbpath /data/db1
mongod --replSet myReplicaSet --port 27018 --dbpath /data/db2
mongod --replSet myReplicaSet --port 27019 --dbpath /data/db3
Replica Set’i başlatın:
mongo --port 27017
rs.initiate({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
});
6. Örnek Senaryolar
6.1. Sharding ile Horizontal Scaling:
# Shard'ları başlatma
mongod --shardsvr --replSet shardReplSet1 --port 27022 --dbpath /data/shard1
mongod --shardsvr --replSet shardReplSet2 --port 27023 --dbpath /data/shard2
# Shard'ları mongos'a ekleme
mongo --port 27017
sh.addShard("shardReplSet1/localhost:27022");
sh.addShard("shardReplSet2/localhost:27023");
# Sharding'i etkinleştirme
sh.enableSharding("myDatabase");
sh.shardCollection("myDatabase.myCollection", { shardKey: 1 });
6.2. Replication ile Yüksek Kullanılabilirlik:
# Replica Set'i başlatma
mongod --replSet myReplicaSet --port 27017 --dbpath /data/db1
mongod --replSet myReplicaSet --port 27018 --dbpath /data/db2
mongod --replSet myReplicaSet --port 27019 --dbpath /data/db3
# Replica Set'i yapılandırma
mongo --port 27017
rs.initiate({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
});
Data Modeling Best Practices
Veri modelleme pattern’leri
1. Veri Modelleme Pattern’leri Nedir ve Neden Önemlidir?
Veri Modelleme Pattern’leri, MongoDB’de verilerin nasıl yapılandırılacağına dair en iyi uygulamaları ve tasarım kalıplarını içerir. Bu pattern’ler, performansı artırmak, sorguları optimize etmek ve veri bütünlüğünü sağlamak için kullanılır.
Neden Önemlidir?
- Performans: Doğru veri modelleme, sorgu performansını artırır.
- Ölçeklenebilirlik: Veri modeli, sistemin ölçeklenebilirliğini etkiler.
- Veri Bütünlüğü: Veri modeli, veri bütünlüğünü ve tutarlılığını sağlar.
- Geliştirme Kolaylığı: İyi bir veri modeli, uygulama geliştirmeyi kolaylaştırır.
2. Temel Veri Modelleme Pattern’leri
MongoDB’de yaygın olarak kullanılan temel veri modelleme pattern’leri şunlardır:
- Embedded Documents Pattern (Gömülü Belge Pattern’i)
- Reference Pattern (Referans Pattern’i)
- Extended Reference Pattern (Genişletilmiş Referans Pattern’i)
- Subset Pattern (Alt Küme Pattern’i)
- Bucket Pattern (Kova Pattern’i)
- Computed Pattern (Hesaplanmış Pattern)
- Polymorphic Pattern (Çok Biçimli Pattern)
- Schema Versioning Pattern (Şema Sürümleme Pattern’i)
3. Embedded Documents Pattern (Gömülü Belge Pattern’i)
Bu pattern, ilişkili verileri tek bir belge içinde gömülü olarak saklar. Özellikle birbirine sıkıca bağlı veriler için uygundur.
Avantajları:
- Hızlı Erişim: İlişkili verilere tek bir sorguyla erişilir.
- Atomik İşlemler: Tek bir belge üzerinde atomik işlemler yapılabilir.
Örnek:
{
_id: 1,
name: "John Doe",
address: {
street: "123 Main St",
city: "Anytown",
state: "CA",
zip: "12345"
},
orders: [
{ product: "Laptop", quantity: 1, price: 1200 },
{ product: "Mouse", quantity: 2, price: 25 }
]
}
4. Reference Pattern (Referans Pattern’i)
Bu pattern, ilişkili verileri farklı belgelerde saklar ve bu belgeler arasında referanslar kullanır. Özellikle büyük ve sık güncellenen veriler için uygundur.
Avantajları:
- Veri Tekrarını Azaltma: Aynı verilerin tekrarını önler.
- Esneklik: Veri yapısını daha esnek hale getirir.
Örnek:
// Kullanıcı belgesi
{
_id: 1,
name: "John Doe",
address: {
street: "123 Main St",
city: "Anytown",
state: "CA",
zip: "12345"
}
}
// Sipariş belgesi
{
_id: 101,
user_id: 1,
product: "Laptop",
quantity: 1,
price: 1200
}
5. Extended Reference Pattern (Genişletilmiş Referans Pattern’i)
Bu pattern, referans pattern’inin bir varyasyonudur. İlişkili belgelerde sık kullanılan alanları referans belgesine ekler.
Avantajları:
- Sorgu Performansı: Sık kullanılan alanlar için ek sorgulara gerek kalmaz.
- Veri Tekrarını Azaltma: Yalnızca gerekli alanlar tekrarlanır.
Örnek:
// Kullanıcı belgesi
{
_id: 1,
name: "John Doe",
address: {
street: "123 Main St",
city: "Anytown",
state: "CA",
zip: "12345"
}
}
// Sipariş belgesi
{
_id: 101,
user_id: 1,
user_name: "John Doe",
product: "Laptop",
quantity: 1,
price: 1200
}
6. Subset Pattern (Alt Küme Pattern’i)
Bu pattern, büyük belgelerin sık kullanılan bir alt kümesini ayrı bir belgede saklar. Özellikle büyük belgelerde performansı artırır.
Avantajları:
- Performans: Sık kullanılan verilere hızlı erişim sağlar.
- Bellek Kullanımı: Bellek kullanımını optimize eder.
Örnek:
// Tam kullanıcı belgesi
{
_id: 1,
name: "John Doe",
address: {
street: "123 Main St",
city: "Anytown",
state: "CA",
zip: "12345"
},
orders: [
{ product: "Laptop", quantity: 1, price: 1200 },
{ product: "Mouse", quantity: 2, price: 25 }
],
preferences: {
newsletter: true,
notifications: false
}
}
// Alt küme belgesi
{
_id: 1,
name: "John Doe",
orders: [
{ product: "Laptop", quantity: 1, price: 1200 },
{ product: "Mouse", quantity: 2, price: 25 }
]
}
7. Bucket Pattern (Kova Pattern’i)
Bu pattern, zaman serisi verilerini veya büyük veri kümelerini “kova”lara böler. Özellikle zaman serisi verileri için uygundur.
Avantajları:
- Performans: Büyük veri kümelerini daha küçük parçalara böler.
- Ölçeklenebilirlik: Veri büyümesini yönetmeyi kolaylaştırır.
Örnek:
{
_id: "2023-10-01",
sensor_id: 101,
readings: [
{ timestamp: "2023-10-01T00:00:00Z", value: 25 },
{ timestamp: "2023-10-01T01:00:00Z", value: 26 }
]
}
8. Computed Pattern (Hesaplanmış Pattern)
Bu pattern, sık hesaplanan değerleri önceden hesaplayarak saklar. Özellikle karmaşık hesaplamalar için uygundur.
Avantajları:
- Performans: Sık hesaplanan değerler için sorgu performansını artırır.
- Kaynak Tasarrufu: Hesaplama maliyetini azaltır.
Örnek:
{
_id: 1,
name: "John Doe",
total_orders: 5,
total_spent: 1250
}
9. Polymorphic Pattern (Çok Biçimli Pattern)
Bu pattern, farklı türdeki belgeleri aynı koleksiyonda saklar. Özellikle farklı türdeki veriler için uygundur.
Avantajları:
- Esneklik: Farklı türdeki verileri aynı koleksiyonda saklar.
- Sorgu Kolaylığı: Tek bir sorguyla farklı türdeki verilere erişim sağlar.
Örnek:
{
_id: 1,
type: "book",
title: "MongoDB Guide",
author: "John Doe",
pages: 300
}
{
_id: 2,
type: "movie",
title: "MongoDB: The Movie",
director: "Jane Doe",
duration: 120
}
10. Schema Versioning Pattern (Şema Sürümleme Pattern’i)
Bu pattern, şema değişikliklerini yönetmek için kullanılır. Özellikle şema değişikliklerinin sık olduğu durumlarda uygundur.
Avantajları:
- Uyumluluk: Eski ve yeni şemaları aynı anda destekler.
- Geçiş Kolaylığı: Şema değişikliklerini yönetmeyi kolaylaştırır.
Örnek:
{
_id: 1,
name: "John Doe",
schema_version: 2,
address: {
street: "123 Main St",
city: "Anytown",
state: "CA",
zip: "12345"
}
}
Anti-pattern’lerden kaçınma
1. Anti-pattern Nedir ve Neden Kaçınılmalıdır?
Anti-pattern, yaygın olarak kullanılan ancak etkisiz veya zararlı olan bir tasarım veya uygulama şeklidir. MongoDB’de anti-pattern’ler, genellikle performansı düşürür, veri bütünlüğünü zayıflatır ve sistemin ölçeklenebilirliğini engeller.
Neden Kaçınılmalıdır?
- Performans Sorunları: Anti-pattern’ler, sorgu performansını düşürür.
- Veri Bütünlüğü: Veri tutarlılığını ve bütünlüğünü zayıflatır.
- Bakım Zorluğu: Sistemin bakımını ve genişletilmesini zorlaştırır.
- Ölçeklenebilirlik: Sistemin ölçeklenebilirliğini engeller.
2. Yaygın MongoDB Anti-pattern’leri
MongoDB’de sıkça karşılaşılan anti-pattern’ler şunlardır:
- Büyük ve Derin İç İçe Belgeler
- Aşırı Normalizasyon
- Sık Güncellenen Büyük Belgeler
- Çok Fazla Referans Kullanma
- Gereksiz İndeksleme
- Sorgularda $where Kullanımı
- Büyük Diziler ve Büyük Belgeler
- Zaman Serisi Verilerini Yanlış Modelleme
3. Büyük ve Derin İç İçe Belgeler
Bu anti-pattern, belgelerin çok büyük ve derin iç içe yapılar halinde tasarlanmasıdır. Bu, sorgu performansını düşürür ve bellek kullanımını artırır.
Örnek:
{
_id: 1,
name: "John Doe",
orders: [
{
order_id: 101,
products: [
{
product_id: 201,
details: {
name: "Laptop",
specifications: {
cpu: "Intel i7",
ram: "16GB",
storage: "512GB SSD"
}
}
}
]
}
]
}
Çözüm:
- Alt Belgeleri Ayırma: Büyük ve derin iç içe belgeleri daha küçük parçalara bölün.
- Bucket Pattern: Zaman serisi verileri için bucket pattern kullanın.
4. Aşırı Normalizasyon
Bu anti-pattern, ilişkisel veritabanı yaklaşımını MongoDB’ye uygulayarak aşırı normalizasyon yapmaktır. Bu, MongoDB’nin esnek şema yapısını kullanmamak anlamına gelir.
Örnek:
// Kullanıcı belgesi
{
_id: 1,
name: "John Doe"
}
// Adres belgesi
{
_id: 101,
user_id: 1,
street: "123 Main St",
city: "Anytown",
state: "CA",
zip: "12345"
}
Çözüm:
- Embedded Documents: İlişkili verileri tek bir belgede saklayın.
- Extended Reference Pattern: Sık kullanılan alanları referans belgesine ekleyin.
5. Sık Güncellenen Büyük Belgeler
Bu anti-pattern, sık güncellenen büyük belgelerin kullanılmasıdır. Bu, yazma performansını düşürür ve bellek kullanımını artırır.
Örnek:
{
_id: 1,
name: "John Doe",
orders: [
{ order_id: 101, product: "Laptop", quantity: 1, price: 1200 },
{ order_id: 102, product: "Mouse", quantity: 2, price: 25 }
],
preferences: {
newsletter: true,
notifications: false
}
}
Çözüm:
- Belgeleri Ayırma: Sık güncellenen alanları ayrı belgelerde saklayın.
- Subset Pattern: Sık kullanılan verileri ayrı bir belgede saklayın.
6. Çok Fazla Referans Kullanma
Bu anti-pattern, ilişkili verileri çok fazla referans kullanarak saklamaktır. Bu, sorgu performansını düşürür ve veri bütünlüğünü zayıflatır.
Örnek:
// Kullanıcı belgesi
{
_id: 1,
name: "John Doe"
}
// Sipariş belgesi
{
_id: 101,
user_id: 1,
product_id: 201,
quantity: 1,
price: 1200
}
// Ürün belgesi
{
_id: 201,
name: "Laptop",
price: 1200
}
Çözüm:
- Embedded Documents: İlişkili verileri tek bir belgede saklayın.
- Extended Reference Pattern: Sık kullanılan alanları referans belgesine ekleyin.
7. Gereksiz İndeksleme
Bu anti-pattern, gereksiz yere çok fazla indeks oluşturmaktır. Bu, yazma performansını düşürür ve disk alanını gereksiz yere tüketir.
Örnek:
db.myCollection.createIndex({ name: 1 });
db.myCollection.createIndex({ age: 1 });
db.myCollection.createIndex({ name: 1, age: 1 });
Çözüm:
- İndeks Analizi: Sorgu performansını analiz ederek gereksiz indeksleri kaldırın.
- Bileşik İndeks: Birden fazla alan için bileşik indeks kullanın.
8. Sorgularda $where Kullanımı
Bu anti-pattern, sorgularda $where
operatörünü kullanmaktır. Bu, sorgu performansını düşürür ve güvenlik riskleri oluşturur.
Örnek:
db.myCollection.find({ $where: "this.age > 30" });
Çözüm:
- Standart Sorgu Operatörleri:
$where
yerine standart sorgu operatörlerini kullanın. - İndeksleme: Sorgu performansını artırmak için indeksler kullanın.
9. Büyük Diziler ve Büyük Belgeler
Bu anti-pattern, büyük diziler ve büyük belgeler kullanmaktır. Bu, bellek kullanımını artırır ve sorgu performansını düşürür.
Örnek:
{
_id: 1,
name: "John Doe",
logs: [
"log1", "log2", "log3", ..., "log100000"
]
}
Çözüm:
- Bucket Pattern: Büyük dizileri daha küçük parçalara bölün.
- Alt Belgeleri Ayırma: Büyük belgeleri daha küçük parçalara bölün.
10. Zaman Serisi Verilerini Yanlış Modelleme
Bu anti-pattern, zaman serisi verilerini yanlış modellemektir. Bu, sorgu performansını düşürür ve veri büyümesini yönetmeyi zorlaştırır.
Örnek:
{
_id: 1,
sensor_id: 101,
timestamp: "2023-10-01T00:00:00Z",
value: 25
}
Çözüm:
- Bucket Pattern: Zaman serisi verilerini bucket’lara bölün.
- TTL İndeksi: Eski verileri otomatik olarak silmek için TTL indeksi kullanın.
Schema versiyonlama
Schema Versiyonlama Neden Önemlidir?
- Uyumluluk: Uygulamanızın farklı sürümleri farklı şema yapılarını kullanabilir. Schema versiyonlama, bu sürümler arasında uyumluluk sağlar.
- Veri Bütünlüğü: Şema değişiklikleri sırasında veri kaybını önlemek ve veri bütünlüğünü korumak önemlidir.
- Geriye Dönük Uyumluluk: Eski verilerin yeni şema yapısıyla çalışabilmesini sağlar.
- Yeniden Yapılandırma: Şema değişiklikleri sırasında veritabanınızı yeniden yapılandırmanız gerekebilir. Schema versiyonlama bu süreci yönetilebilir hale getirir.
Schema Versiyonlama Nasıl Yapılır?
Schema versiyonlama, genellikle belgelerinize bir schema_version
veya version
alanı ekleyerek yapılır. Bu alan, belgenin hangi şema sürümüne sahip olduğunu belirtir. Uygulamanız, bu alanı kontrol ederek belgeleri doğru şekilde işleyebilir.
Örnek Senaryo
Diyelim ki bir kullanıcı koleksiyonunuz var ve bu koleksiyonun şemasını zaman içinde değiştirmeniz gerekiyor. İlk başta şema şu şekilde olabilir:
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "John Doe",
"email": "john@example.com"
}
Daha sonra, uygulamanızın yeni bir sürümünde, kullanıcıların yaş bilgisini de saklamak istiyorsunuz. Yeni şema şu şekilde olabilir:
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "John Doe",
"email": "john@example.com",
"age": 30,
"schema_version": 2
}
Burada schema_version
alanı, belgenin yeni şema sürümüne sahip olduğunu belirtir.
Schema Versiyonlama Adımları
- Versiyon Alanı Eklemek: Belgelerinize bir
schema_version
alanı ekleyin. Bu alan, belgenin hangi şema sürümüne sahip olduğunu belirtir. - Mevcut Belgeleri Güncellemek: Eski şema sürümüne sahip belgeleri yeni şema sürümüne dönüştürmek için bir migrasyon scripti yazın.
- Uygulama Mantığını Güncellemek: Uygulamanızın, farklı şema sürümlerini destekleyecek şekilde güncellenmesi gerekir. Örneğin,
schema_version
alanını kontrol ederek belgeleri doğru şekilde işleyebilirsiniz. - Test Etmek: Yeni şema sürümünü ve migrasyon scriptlerini test edin. Veri kaybı veya bozulma olmadığından emin olun.
Kod Örneği
Aşağıda, MongoDB’de schema versiyonlamayı nasıl uygulayabileceğinize dair bir örnek bulunmaktadır.
1. Versiyon Alanı Eklemek
// Yeni bir belge eklerken schema_version alanını ekleyin
db.users.insert({
name: "Jane Doe",
email: "jane@example.com",
age: 25,
schema_version: 2
});
2. Mevcut Belgeleri Güncellemek
// schema_version 1 olan belgeleri schema_version 2'ye güncelle
db.users.updateMany(
{ schema_version: { $exists: false } }, // schema_version alanı olmayan belgeler
[
{ $set: { schema_version: 1 } }, // schema_version alanını ekle
{ $set: { age: null } } // age alanını ekle ve varsayılan değer ata
]
);
3. Uygulama Mantığını Güncellemek
// Kullanıcı bilgilerini alırken schema_version'a göre işlem yap
const user = db.users.findOne({ _id: ObjectId("507f1f77bcf86cd799439011") });
if (user.schema_version === 1) {
// Eski şema sürümü için işlemler
console.log(`User: ${user.name}, Email: ${user.email}`);
} else if (user.schema_version === 2) {
// Yeni şema sürümü için işlemler
console.log(`User: ${user.name}, Email: ${user.email}, Age: ${user.age}`);
}
Schema Versiyonlama Stratejileri
- İleriye Dönük Uyumluluk: Yeni şema sürümleri, eski sürümlerle uyumlu olacak şekilde tasarlanmalıdır. Örneğin, yeni alanlar eklerken bu alanların varsayılan değerlerini belirleyebilirsiniz.
- Migrasyon Scriptleri: Büyük veri kümeleri için migrasyon scriptleri yazmak, veri bütünlüğünü korumanın etkili bir yoludur.
- Çift Yazma (Dual Writing): Yeni ve eski şema sürümlerini aynı anda destekleyerek, geçiş sürecini daha sorunsuz hale getirebilirsiniz.
- Sürüm Kontrolü: Şema değişikliklerini sürüm kontrol sistemi (Git gibi) ile takip edin. Bu, değişiklikleri geri almayı kolaylaştırır.
Migration stratejileri
Migration Stratejileri Neden Önemlidir?
- Veri Bütünlüğü: Migration sürecinde veri kaybı veya bozulma olmamasını sağlar.
- Uygulama Duruş Süresi: Migration işlemleri sırasında uygulamanın çalışmaya devam etmesini sağlar.
- Geriye Dönük Uyumluluk: Eski verilerin yeni şema yapısıyla uyumlu olmasını sağlar.
- Ölçeklenebilirlik: Büyük veri kümeleri üzerinde migration işlemlerini etkili bir şekilde yönetir.
Migration Stratejileri Türleri
MongoDB’de migration stratejileri genellikle aşağıdaki yöntemlerle uygulanır:
- Online Migration (Çevrimiçi Geçiş)
- Offline Migration (Çevrimdışı Geçiş)
- Rolling Migration (Kademeli Geçiş)
- Dual Writing (Çift Yazma)
Şimdi bu stratejileri detaylı bir şekilde inceleyelim.
1. Online Migration (Çevrimiçi Geçiş)
Online migration, uygulamanın çalışmaya devam ettiği sırada veritabanı şemasını güncelleme işlemidir. Bu yöntem, uygulamanın durmasını gerektirmez ve genellikle küçük ölçekli değişiklikler için kullanılır.
Avantajları:
- Uygulama duruş süresi yoktur.
- Kullanıcılar için kesintisiz bir deneyim sunar.
Dezavantajları:
- Büyük veri kümeleri için yavaş olabilir.
- Eşzamanlı işlemler sırasında tutarsızlıklar oluşabilir.
Örnek Senaryo:
Kullanıcı koleksiyonuna yeni bir alan (age
) eklemek istiyorsunuz.
// Mevcut belgeleri güncelle
db.users.updateMany(
{}, // Tüm belgeleri seç
{ $set: { age: null } } // age alanını ekle ve varsayılan değer ata
);
Bu işlem sırasında uygulama çalışmaya devam edebilir. Ancak, age
alanı henüz doldurulmamış belgeler için uygulamanızın bu durumu ele alması gerekir.
2. Offline Migration (Çevrimdışı Geçiş)
Offline migration, uygulamanın durdurulduğu ve veritabanı üzerinde değişikliklerin yapıldığı bir yöntemdir. Bu yöntem, büyük ölçekli değişiklikler veya veri bütünlüğünün kritik olduğu durumlar için uygundur.
Avantajları:
- Veri bütünlüğü daha kolay sağlanır.
- Büyük veri kümeleri üzerinde daha hızlı çalışabilir.
Dezavantajları:
- Uygulama duruş süresi gerektirir.
- Kullanıcılar için kesintiye neden olur.
Örnek Senaryo:
Kullanıcı koleksiyonundaki email
alanını email_address
olarak yeniden adlandırmak istiyorsunuz.
// Uygulamayı durdur ve migration işlemini gerçekleştir
db.users.updateMany(
{}, // Tüm belgeleri seç
{ $rename: { email: "email_address" } } // email alanını yeniden adlandır
);
Bu işlem sırasında uygulamanın durdurulması gerekir.
3. Rolling Migration (Kademeli Geçiş)
Rolling migration, veritabanı şemasını kademeli olarak güncelleme işlemidir. Bu yöntem, büyük ölçekli sistemlerde ve dağıtık mimarilerde sıkça kullanılır.
Avantajları:
- Uygulama duruş süresi yoktur.
- Büyük veri kümeleri üzerinde etkilidir.
Dezavantajları:
- Karmaşık bir süreç olabilir.
- Farklı sürümler arasında tutarsızlıklar oluşabilir.
Örnek Senaryo:
Kullanıcı koleksiyonuna yeni bir alan (age
) eklemek ve bu alanı kademeli olarak doldurmak istiyorsunuz.
// Yeni belgeler için age alanını ekle
db.users.insert({
name: "Jane Doe",
email: "jane@example.com",
age: 25
});
// Eski belgeleri kademeli olarak güncelle
db.users.updateMany(
{ age: { $exists: false } }, // age alanı olmayan belgeleri seç
{ $set: { age: null } } // age alanını ekle ve varsayılan değer ata
);
Bu işlem sırasında uygulama çalışmaya devam eder ve age
alanı kademeli olarak doldurulur.
4. Dual Writing (Çift Yazma)
Dual writing, hem eski hem de yeni şema yapısını aynı anda destekleyen bir yöntemdir. Bu yöntem, geçiş sürecini daha sorunsuz hale getirir.
Avantajları:
- Uygulama duruş süresi yoktur.
- Eski ve yeni şema yapıları arasında tutarsızlık riski azdır.
Dezavantajları:
- Daha fazla depolama alanı gerektirir.
- Karmaşık bir süreç olabilir.
Örnek Senaryo:
Kullanıcı koleksiyonundaki email
alanını email_address
olarak yeniden adlandırmak ve her iki alanı da aynı anda kullanmak istiyorsunuz.
// Yeni belgeler için her iki alanı da ekle
db.users.insert({
name: "John Doe",
email: "john@example.com",
email_address: "john@example.com"
});
// Eski belgeleri güncelle
db.users.updateMany(
{}, // Tüm belgeleri seç
{ $set: { email_address: "$email" } } // email alanını email_address'e kopyala
);
Bu işlem sırasında uygulama çalışmaya devam eder ve her iki alan da kullanılabilir.
Migration Stratejileri İçin En İyi Uygulamalar
- Yedekleme: Migration işlemlerine başlamadan önce veritabanınızın yedeğini alın.
- Test Ortamı: Migration işlemlerini önce test ortamında deneyin.
- İzleme: Migration sürecini izleyin ve olası hataları tespit edin.
- Geri Alma Planı: Migration işlemi başarısız olursa geri alma planı hazırlayın.
- Dokümantasyon: Migration sürecini detaylı bir şekilde dokümante edin.
Data integrity sağlama yöntemleri
Veri Bütünlüğü Neden Önemlidir?
- Tutarlılık: Veritabanındaki verilerin her zaman tutarlı olması, uygulamanın doğru çalışmasını sağlar.
- Güvenilirlik: Verilerin güvenilir olması, kullanıcıların sisteme olan güvenini artırır.
- Veri Kaybını Önleme: Veri bütünlüğü, yanlış veya eksik veri girişlerini önler.
- İş Kurallarının Uygulanması: Veri bütünlüğü, iş kurallarının veritabanı düzeyinde uygulanmasını sağlar.
MongoDB’de Veri Bütünlüğünü Sağlama Yöntemleri
MongoDB’de veri bütünlüğünü sağlamak için aşağıdaki yöntemler kullanılabilir:
- Schema Validation (Şema Doğrulama)
- Atomic Operations (Atomik İşlemler)
- Referential Integrity (Referans Bütünlüğü)
- Transactions (İşlemler)
- Unique Indexes (Benzersiz İndeksler)
- Veri Doğrulama Katmanı (Uygulama Katmanında)
Şimdi bu yöntemleri detaylı bir şekilde inceleyelim.
1. Schema Validation (Şema Doğrulama)
MongoDB, JSON Schema kullanarak belge yapısını doğrulama imkanı sunar. Bu, belgelerin belirli bir şemaya uygun olup olmadığını kontrol eder.
Avantajları:
- Veri girişlerinin belirli kurallara uygun olmasını sağlar.
- Yanlış veri girişlerini önler.
Örnek Senaryo:
Kullanıcı koleksiyonundaki belgelerin name
ve email
alanlarını zorunlu hale getirmek ve email
alanının geçerli bir e-posta formatında olmasını sağlamak istiyorsunuz.
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: {
bsonType: "string",
description: "Name must be a string and is required."
},
email: {
bsonType: "string",
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
description: "Email must be a valid email address and is required."
}
}
}
}
});
Bu şema doğrulama kuralı, name
ve email
alanlarının zorunlu olduğunu ve email
alanının geçerli bir e-posta formatında olması gerektiğini belirtir.
2. Atomic Operations (Atomik İşlemler)
MongoDB, tek bir belge üzerinde yapılan işlemlerin atomik olduğunu garanti eder. Bu, bir işlemin ya tamamen başarılı olacağı ya da hiç gerçekleşmeyeceği anlamına gelir.
Avantajları:
- Veri tutarlılığını sağlar.
- Aynı belge üzerinde eşzamanlı işlemler sırasında çakışmaları önler.
Örnek Senaryo:
Bir kullanıcının bakiyesini güncellemek istiyorsunuz. Bu işlemin atomik olması gerekiyor.
db.users.updateOne(
{ _id: ObjectId("507f1f77bcf86cd799439011") },
{ $inc: { balance: 100 } } // Bakiyeyi 100 artır
);
Bu işlem atomiktir ve aynı belge üzerinde eşzamanlı işlemler sırasında tutarlılık sağlar.
3. Referential Integrity (Referans Bütünlüğü)
MongoDB, ilişkisel veritabanları gibi otomatik referans bütünlüğü sağlamaz. Ancak, uygulama katmanında bu bütünlüğü sağlayabilirsiniz.
Avantajları:
- İlişkili belgeler arasında tutarlılık sağlar.
- Eksik veya geçersiz referansları önler.
Örnek Senaryo:
Bir sipariş koleksiyonunda, her siparişin bir kullanıcıya ait olması gerekiyor. Kullanıcı silindiğinde, ilişkili siparişlerin de silinmesi gerekiyor.
// Kullanıcı silindiğinde ilişkili siparişleri sil
db.users.deleteOne({ _id: ObjectId("507f1f77bcf86cd799439011") });
db.orders.deleteMany({ userId: ObjectId("507f1f77bcf86cd799439011") });
Bu işlem, referans bütünlüğünü uygulama katmanında sağlar.
4. Transactions (İşlemler)
MongoDB, çok belgeli işlemleri destekler. Bu, birden fazla belge üzerinde yapılan işlemlerin atomik olmasını sağlar.
Avantajları:
- Birden fazla belge üzerinde tutarlılık sağlar.
- Karmaşık işlemleri güvenle gerçekleştirir.
Örnek Senaryo:
Bir kullanıcının bakiyesini güncellerken, aynı anda bir işlem kaydı eklemek istiyorsunuz.
const session = db.getMongo().startSession();
session.startTransaction();
try {
const users = session.getDatabase("mydb").users;
const transactions = session.getDatabase("mydb").transactions;
users.updateOne(
{ _id: ObjectId("507f1f77bcf86cd799439011") },
{ $inc: { balance: -100 } }
);
transactions.insertOne({
userId: ObjectId("507f1f77bcf86cd799439011"),
amount: -100,
date: new Date()
});
session.commitTransaction();
} catch (error) {
session.abortTransaction();
} finally {
session.endSession();
}
Bu işlem, hem bakiyeyi günceller hem de bir işlem kaydı ekler. İşlem sırasında bir hata olursa, tüm işlem geri alınır.
5. Unique Indexes (Benzersiz İndeksler)
Benzersiz indeksler, bir koleksiyondaki belirli bir alanın benzersiz olmasını sağlar. Bu, veri bütünlüğünü korumak için etkili bir yöntemdir.
Avantajları:
- Yinelenen verileri önler.
- Veri tutarlılığını artırır.
Örnek Senaryo:
Kullanıcı koleksiyonunda email
alanının benzersiz olmasını istiyorsunuz.
db.users.createIndex({ email: 1 }, { unique: true });
Bu indeks, email
alanının benzersiz olmasını sağlar. Aynı e-posta adresiyle birden fazla belge eklenemez.
6. Veri Doğrulama Katmanı (Uygulama Katmanında)
Veri doğrulama işlemlerini uygulama katmanında da gerçekleştirebilirsiniz. Bu, MongoDB’nin esnek yapısını korurken veri bütünlüğünü sağlamanın etkili bir yoludur.
Avantajları:
- Esneklik sağlar.
- İş kurallarını uygulama katmanında tanımlayabilirsiniz.
Örnek Senaryo:
Kullanıcı kaydı sırasında email
alanının geçerli bir e-posta adresi olup olmadığını kontrol etmek istiyorsunuz.
function isValidEmail(email) {
const regex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return regex.test(email);
}
if (isValidEmail("john@example.com")) {
db.users.insertOne({ name: "John Doe", email: "john@example.com" });
} else {
console.log("Geçersiz e-posta adresi!");
}
Modern MongoDB Özellikleri
Change streams
Change Streams Nedir?
Change Streams, MongoDB koleksiyonlarındaki veya veritabanlarındaki değişiklikleri gerçek zamanlı olarak izlemenizi sağlar. Bu değişiklikler şunları içerebilir:
- Yeni belge ekleme (
insert
) - Belge güncelleme (
update
) - Belge silme (
delete
) - Veritabanı veya koleksiyon düzeyindeki diğer değişiklikler
Change Streams, MongoDB’nin replica set veya sharded cluster yapılarında çalışır ve değişiklikleri bir akış (stream) olarak sunar. Bu akış, uygulamanızın değişikliklere anında tepki vermesini sağlar.
Change Streams Neden Önemlidir?
- Gerçek Zamanlı Veri İzleme: Veritabanındaki değişiklikleri anında takip edebilirsiniz.
- Olay Odaklı Mimari: Değişikliklere dayalı olarak tetiklenen işlemler oluşturabilirsiniz.
- Veri Senkronizasyonu: Farklı sistemler arasında veri senkronizasyonunu kolaylaştırır.
- Audit Logging: Veritabanındaki değişiklikleri kaydederek denetim (audit) amaçlı kullanabilirsiniz.
Change Streams Nasıl Çalışır?
Change Streams, MongoDB’nin oplog (operations log) mekanizmasını kullanır. Oplog, MongoDB’de yapılan tüm değişiklikleri kaydeden özel bir koleksiyondur. Change Streams, bu oplog’u izleyerek değişiklikleri yakalar ve uygulamanıza iletir.
Change Streams, aşağıdaki durumlarda kullanılabilir:
- Tek bir koleksiyondaki değişiklikleri izlemek.
- Bir veritabanındaki tüm koleksiyonlardaki değişiklikleri izlemek.
- Bir MongoDB kümesindeki tüm veritabanlarındaki değişiklikleri izlemek.
Change Streams Kullanım Senaryoları
- Gerçek Zamanlı Bildirimler: Kullanıcılara yeni veri eklendiğinde veya güncellendiğinde bildirim göndermek.
- Veri Senkronizasyonu: Farklı sistemler veya mikroservisler arasında veri senkronizasyonu sağlamak.
- Audit Logging: Veritabanındaki değişiklikleri kaydederek denetim amaçlı kullanmak.
- Cache Güncelleme: Veritabanındaki değişikliklere göre önbelleği (cache) güncellemek.
Change Streams Kullanımı
Change Streams, MongoDB sürücüleri (drivers) veya MongoDB Shell üzerinden kullanılabilir. Aşağıda, Node.js ve MongoDB Shell üzerinden Change Streams kullanım örnekleri bulunmaktadır.
1. MongoDB Shell ile Change Streams Kullanımı
MongoDB Shell üzerinden bir koleksiyondaki değişiklikleri izlemek için aşağıdaki kodu kullanabilirsiniz:
// Koleksiyondaki değişiklikleri izle
const changeStream = db.collection("users").watch();
changeStream.on("change", (change) => {
print(JSON.stringify(change, null, 2));
});
Bu kod, users
koleksiyonundaki değişiklikleri izler ve her değişikliği konsola yazdırır.
2. Node.js ile Change Streams Kullanımı
Node.js üzerinden MongoDB Change Streams kullanmak için aşağıdaki örnek kodu kullanabilirsiniz:
const { MongoClient } = require("mongodb");
async function run() {
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db("mydb");
const collection = database.collection("users");
// Change Stream'i başlat
const changeStream = collection.watch();
// Değişiklikleri dinle
changeStream.on("change", (change) => {
console.log("Değişiklik tespit edildi:", change);
});
console.log("Change Stream dinleniyor...");
} catch (error) {
console.error("Hata:", error);
}
}
run();
Bu kod, users
koleksiyonundaki değişiklikleri dinler ve her değişikliği konsola yazdırır.
Change Streams Çıktısı Örneği
Change Streams, aşağıdaki gibi bir çıktı üretir:
{
"_id": {
"_data": "8260B1A2A7000000012B022C0100296E5A1004..."
},
"operationType": "insert",
"fullDocument": {
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "John Doe",
"email": "john@example.com"
},
"ns": {
"db": "mydb",
"coll": "users"
},
"documentKey": {
"_id": ObjectId("507f1f77bcf86cd799439011")
}
}
Bu çıktıda:
operationType
: Değişiklik türünü belirtir (insert
,update
,delete
vb.).fullDocument
: Değişikliğe uğrayan belgenin tam halini içerir.ns
: Değişikliğin gerçekleştiği veritabanı ve koleksiyon bilgisini içerir.documentKey
: Değişikliğe uğrayan belgenin_id
değerini içerir.
Change Streams ile Filtreleme
Change Streams, belirli türdeki değişiklikleri filtrelemek için kullanılabilir. Örneğin, sadece insert
işlemlerini dinlemek istiyorsanız:
const pipeline = [
{ $match: { operationType: "insert" } }
];
const changeStream = db.collection("users").watch(pipeline);
changeStream.on("change", (change) => {
print(JSON.stringify(change, null, 2));
});
Bu kod, sadece insert
işlemlerini dinler ve diğer değişiklikleri görmezden gelir.
Change Streams ile İşlemleri Geri Alma (Resume Token)
Change Streams, bir resume token kullanarak işlemleri geri alabilir. Bu, uygulamanızın kapatılıp yeniden başlatılması durumunda, kaldığınız yerden devam etmenizi sağlar.
let resumeToken;
const changeStream = db.collection("users").watch();
changeStream.on("change", (change) => {
console.log("Değişiklik:", change);
resumeToken = change._id; // Resume token'ı kaydet
});
// Uygulama yeniden başlatıldığında
const newChangeStream = db.collection("users").watch([], { resumeAfter: resumeToken });
newChangeStream.on("change", (change) => {
console.log("Yeni değişiklik:", change);
});
Time series collections
Time Series Collections Nedir?
Time Series Collections, MongoDB 5.0 sürümüyle birlikte tanıtılan bir özelliktir. Bu özellik, zaman serisi verilerini depolamak ve yönetmek için optimize edilmiş bir yapı sunar. Zaman serisi verileri, genellikle aşağıdaki özelliklere sahiptir:
- Zaman Damgası (Timestamp): Her veri noktası bir zaman damgası ile ilişkilendirilir.
- Ölçümler (Measurements): Zaman damgasına bağlı olarak toplanan veriler (örneğin, sıcaklık, nem, fiyat vb.).
- Meta Veri (Metadata): Veri noktalarını gruplamak veya sınıflandırmak için kullanılan ek bilgiler (örneğin, sensör ID’si, lokasyon bilgisi vb.).
Time Series Collections, bu tür verileri depolarken aşağıdaki avantajları sunar:
- Verimli Depolama: Zaman serisi verilerini sıkıştırarak depolama alanından tasarruf sağlar.
- Hızlı Sorgulama: Zaman bazlı sorguları hızlı bir şekilde gerçekleştirir.
- Otomatik Veri Yönetimi: Verileri otomatik olarak zaman damgasına göre gruplar ve yönetir.
Time Series Collections Neden Önemlidir?
- Verimlilik: Zaman serisi verilerini depolarken ve sorgularken yüksek performans sağlar.
- Ölçeklenebilirlik: Büyük ölçekli zaman serisi verilerini yönetmek için idealdir.
- Analitik Yetenekler: Zaman serisi verileri üzerinde analiz yapmayı kolaylaştırır.
- Otomatik Optimizasyon: Verileri otomatik olarak optimize eder ve yönetir.
Time Series Collections Nasıl Çalışır?
Time Series Collections, zaman serisi verilerini depolarken aşağıdaki yapıyı kullanır:
- Zaman Damgası (Timestamp): Her veri noktası bir zaman damgası ile ilişkilendirilir.
- Ölçümler (Measurements): Zaman damgasına bağlı olarak toplanan veriler.
- Meta Veri (Metadata): Veri noktalarını gruplamak veya sınıflandırmak için kullanılan ek bilgiler.
MongoDB, bu verileri depolarken otomatik olarak sıkıştırır ve zaman damgasına göre gruplar. Bu, depolama alanından tasarruf sağlar ve sorgulama performansını artırır.
Time Series Collections Kullanım Senaryoları
- IoT (Nesnelerin İnterneti): Sensör verilerini depolamak ve analiz etmek.
- Finans: Hisse senedi fiyatları, döviz kurları gibi finansal verileri izlemek.
- Hava Durumu: Hava durumu verilerini toplamak ve analiz etmek.
- Uygulama Metrikleri: Uygulama performans metriklerini izlemek.
Time Series Collections Kullanımı
Time Series Collections, MongoDB’de özel bir koleksiyon türü olarak oluşturulur. Aşağıda, Time Series Collections oluşturma ve kullanma örnekleri bulunmaktadır.
1. Time Series Collection Oluşturma
Time Series Collection oluşturmak için aşağıdaki komutu kullanabilirsiniz:
db.createCollection("sensorData", {
timeseries: {
timeField: "timestamp", // Zaman damgası alanı
metaField: "metadata", // Meta veri alanı
granularity: "seconds" // Veri gruplama sıklığı (seconds, minutes, hours)
}
});
Bu komut, sensorData
adında bir Time Series Collection oluşturur. timeField
, zaman damgası alanını belirtirken, metaField
meta veri alanını belirtir. granularity
ise verilerin ne sıklıkla gruplanacağını belirtir.
2. Time Series Collection’a Veri Ekleme
Time Series Collection’a veri eklemek için aşağıdaki komutu kullanabilirsiniz:
db.sensorData.insertMany([
{
timestamp: new Date("2023-10-01T10:00:00Z"),
metadata: { sensorId: 1, location: "Ankara" },
temperature: 25,
humidity: 60
},
{
timestamp: new Date("2023-10-01T10:05:00Z"),
metadata: { sensorId: 1, location: "Ankara" },
temperature: 26,
humidity: 58
},
{
timestamp: new Date("2023-10-01T10:10:00Z"),
metadata: { sensorId: 2, location: "İstanbul" },
temperature: 28,
humidity: 55
}
]);
Bu komut, sensorData
koleksiyonuna birden fazla zaman serisi verisi ekler.
3. Time Series Collection’dan Veri Sorgulama
Time Series Collection’dan veri sorgulamak için standart MongoDB sorgularını kullanabilirsiniz. Örneğin, belirli bir sensörün verilerini sorgulamak için:
db.sensorData.find({ "metadata.sensorId": 1 });
Bu sorgu, sensorId
değeri 1 olan sensörün verilerini getirir.
4. Zaman Aralığına Göre Sorgulama
Time Series Collection’dan belirli bir zaman aralığındaki verileri sorgulamak için:
db.sensorData.find({
timestamp: {
$gte: new Date("2023-10-01T10:00:00Z"),
$lt: new Date("2023-10-01T10:10:00Z")
}
});
Bu sorgu, belirtilen zaman aralığındaki verileri getirir.
Time Series Collections ile Analiz
Time Series Collections, zaman serisi verileri üzerinde analiz yapmak için güçlü araçlar sunar. Örneğin, MongoDB’nin Aggregation Framework‘ünü kullanarak verileri analiz edebilirsiniz.
Örnek Senaryo: Ortalama Sıcaklık Hesaplama
Belirli bir sensörün ortalama sıcaklığını hesaplamak için:
db.sensorData.aggregate([
{ $match: { "metadata.sensorId": 1 } }, // Sensör ID'si 1 olan verileri filtrele
{
$group: {
_id: null,
avgTemperature: { $avg: "$temperature" } // Ortalama sıcaklığı hesapla
}
}
]);
Bu sorgu, sensorId
değeri 1 olan sensörün ortalama sıcaklığını hesaplar.
Time Series Collections ile Veri Yönetimi
Time Series Collections, verileri otomatik olarak zaman damgasına göre gruplar ve yönetir. Bu, verilerin depolama alanından tasarruf sağlamasını ve sorgulama performansını artırmasını sağlar. Ayrıca, Time Series Collections, verileri otomatik olarak sıkıştırarak depolama maliyetlerini düşürür.
Graph queries
MongoDB’de Grafik Sorguları (Graph Queries)
Grafik sorguları, özellikle sosyal ağlar, öneri sistemleri, hiyerarşik veri yapıları ve benzeri senaryolarda kullanışlıdır. MongoDB, bu tür sorguları gerçekleştirmek için $graphLookup
operatörünü kullanır. Bu operatör, bir koleksiyon içindeki belgeler arasındaki ilişkileri keşfetmek ve bu ilişkiler üzerinden sorgular yapmak için kullanılır.
$graphLookup
Operatörü
$graphLookup
, bir belge içindeki alanları kullanarak, diğer belgelerle olan ilişkileri bulur ve bu ilişkileri bir grafik olarak yapılandırır. Bu operatör, özyinelemeli (recursive) bir şekilde çalışır ve belirli bir derinliğe kadar ilişkileri keşfeder.
$graphLookup
Sözdizimi
{
$graphLookup: {
from: <collection>,
startWith: <expression>,
connectFromField: <string>,
connectToField: <string>,
as: <string>,
maxDepth: <number>,
depthField: <string>,
restrictSearchWithMatch: <document>
}
}
- from: İlişkilerin aranacağı koleksiyon.
- startWith: Grafik aramasının başlayacağı değer.
- connectFromField: İlişkinin başladığı alan.
- connectToField: İlişkinin hedef alanı.
- as: Sonuçların ekleneceği dizi alanı.
- maxDepth: Maksimum özyineleme derinliği.
- depthField: Her bir sonuç belgesine derinlik bilgisinin ekleneceği alan.
- restrictSearchWithMatch: Aramayı kısıtlamak için bir filtre belgesi.
Örnek Senaryo: Çalışan Hiyerarşisi
Bir şirketteki çalışanların hiyerarşisini modelleyen bir koleksiyonumuz olduğunu varsayalım. Her çalışanın bir _id
alanı ve bir reportsTo
alanı vardır. reportsTo
alanı, çalışanın kime rapor verdiğini belirtir.
db.employees.insertMany([
{ _id: 1, name: "Alice", reportsTo: null },
{ _id: 2, name: "Bob", reportsTo: 1 },
{ _id: 3, name: "Charlie", reportsTo: 1 },
{ _id: 4, name: "David", reportsTo: 2 },
{ _id: 5, name: "Eve", reportsTo: 2 },
{ _id: 6, name: "Frank", reportsTo: 3 }
]);
Bu örnekte, Alice en üst düzey yöneticidir ve Bob ile Charlie ona rapor verir. Bob, David ve Eve’e rapor verirken, Charlie Frank’e rapor verir.
Grafik Sorgusu Örneği
Alice’in tüm altında çalışanları bulmak için aşağıdaki sorguyu kullanabiliriz:
db.employees.aggregate([
{
$match: { name: "Alice" }
},
{
$graphLookup: {
from: "employees",
startWith: "$_id",
connectFromField: "_id",
connectToField: "reportsTo",
as: "subordinates",
maxDepth: 10,
depthField: "depth"
}
}
]);
Bu sorgu, Alice’in tüm altında çalışanları bulur ve subordinates
adlı bir diziye ekler. depthField
kullanarak, her bir çalışanın Alice’ten ne kadar uzakta olduğunu da görebiliriz.
Sonuç
{
"_id": 1,
"name": "Alice",
"reportsTo": null,
"subordinates": [
{ "_id": 2, "name": "Bob", "reportsTo": 1, "depth": 1 },
{ "_id": 3, "name": "Charlie", "reportsTo": 1, "depth": 1 },
{ "_id": 4, "name": "David", "reportsTo": 2, "depth": 2 },
{ "_id": 5, "name": "Eve", "reportsTo": 2, "depth": 2 },
{ "_id": 6, "name": "Frank", "reportsTo": 3, "depth": 2 }
]
}
Bu sonuç, Alice’in tüm altında çalışanları ve her birinin hiyerarşideki derinliğini gösterir.
Grafik Sorgularının Avantajları
- Esneklik: MongoDB’nin esnek şema yapısı, grafik sorgularını uygulamayı kolaylaştırır.
- Performans:
$graphLookup
operatörü, büyük veri kümelerinde bile etkili bir şekilde çalışır. - Karmaşık İlişkiler: Karmaşık ilişkileri analiz etmek ve bu ilişkiler üzerinden sorgular çalıştırmak için idealdir.
Sınırlamalar
- Derinlik Sınırlaması:
maxDepth
parametresi, özyineleme derinliğini sınırlar. Bu, çok derin ilişkilerde performans sorunlarına neden olabilir. - Bellek Kullanımı: Büyük veri kümelerinde,
$graphLookup
operatörü bellek tüketimini artırabilir.
MongoDB Compass kullanımı
MongoDB Compass Nedir?
MongoDB Compass, MongoDB veritabanlarıyla etkileşim kurmak için kullanılan bir GUI aracıdır. Compass, kullanıcıların veritabanı şemalarını görselleştirmesine, sorgular çalıştırmasına, indeksleri yönetmesine ve performans analizi yapmasına olanak tanır. Ayrıca, komut satırı kullanmadan veritabanı işlemlerini gerçekleştirmek isteyenler için ideal bir çözümdür.
MongoDB Compass’ın Temel Özellikleri
Veri Görselleştirme:
- Veritabanındaki koleksiyonları ve belgeleri görsel olarak inceleme imkanı sunar.
- JSON belgelerini ağaç yapısı veya tablo formatında görüntüleyebilirsiniz.
Sorgu Oluşturucu (Query Builder):
- Kullanıcıların grafik arayüz üzerinden sorgular oluşturmasını sağlar.
- Sorgu filtreleri, sıralama ve projeksiyon işlemleri kolayca yapılabilir.
Şema Analizi:
- Koleksiyonların şema yapısını otomatik olarak analiz eder ve görselleştirir.
- Veri tipleri, alanların sıklığı ve benzersiz değerler hakkında bilgi sunar.
Performans Analizi:
- Sorguların performansını analiz eder ve yavaş sorguları tespit eder.
- İndeks önerileri sunarak performansı artırmaya yardımcı olur.
Veri Düzenleme:
- Belgeleri doğrudan GUI üzerinden ekleme, güncelleme ve silme işlemleri yapılabilir.
Aggregation Pipeline Desteği:
- Aggregation pipeline sorgularını görsel olarak oluşturma ve çalıştırma imkanı sunar.
Bağlantı Yönetimi:
- Birden fazla MongoDB bağlantısını yönetebilir ve hızlıca geçiş yapabilirsiniz.
MongoDB Compass Kurulumu
MongoDB Compass, MongoDB’nin resmi web sitesinden ücretsiz olarak indirilebilir. Kurulum işlemi oldukça basittir:
- MongoDB Compass adresine gidin.
- İşletim sisteminize uygun sürümü indirin.
- Kurulum sihirbazını takip ederek Compass’ı yükleyin.
MongoDB Compass Kullanımı
1. Bağlantı Kurma
Compass’ı açtıktan sonra, MongoDB sunucusuna bağlanmak için bağlantı bilgilerini girmeniz gerekiyor. Örneğin, yerel bir MongoDB örneğine bağlanmak için aşağıdaki bağlantı dizesini kullanabilirsiniz:
mongodb://localhost:27017
Eğer kimlik doğrulama gerekiyorsa, kullanıcı adı ve şifre bilgilerini de ekleyebilirsiniz.
2. Koleksiyonları ve Belgeleri Görüntüleme
Bağlantı kurulduktan sonra, sol tarafta veritabanı ve koleksiyonlar listelenir. Bir koleksiyona tıkladığınızda, içindeki belgeleri görüntüleyebilirsiniz. Belgeler, varsayılan olarak JSON formatında gösterilir, ancak tablo formatına da geçiş yapabilirsiniz.
3. Sorgu Oluşturucu ile Sorgulama
Compass, sorgu oluşturucu aracılığıyla kullanıcıların kolayca sorgular yazmasını sağlar. Örneğin, age
alanı 30’dan büyük olan belgeleri bulmak için aşağıdaki adımları izleyebilirsiniz:
- Koleksiyonu seçin.
- “Filter” alanına
{ age: { $gt: 30 } }
yazın. - “Find” butonuna tıklayın.
Sonuçlar, belirtilen filtreye uygun belgeleri gösterecektir.
4. Şema Analizi
Compass, koleksiyonların şema yapısını otomatik olarak analiz eder. Örneğin, bir users
koleksiyonunun şemasını analiz etmek için:
- Koleksiyonu seçin.
- “Schema” sekmesine tıklayın.
Burada, her bir alanın veri tipi, sıklığı ve benzersiz değerleri hakkında bilgi edinebilirsiniz.
5. Aggregation Pipeline Oluşturma
Compass, aggregation pipeline sorgularını görsel olarak oluşturmanıza olanak tanır. Örneğin, orders
koleksiyonundaki toplam sipariş tutarını hesaplamak için:
- Koleksiyonu seçin.
- “Aggregations” sekmesine tıklayın.
- Aşağıdaki pipeline aşamalarını ekleyin:
[
{ $group: { _id: null, totalAmount: { $sum: "$amount" } } }
]
Bu sorgu, tüm siparişlerin toplam tutarını hesaplayacaktır.
6. Veri Düzenleme
Compass üzerinden belgeleri doğrudan düzenleyebilirsiniz. Örneğin, bir belgeyi güncellemek için:
- Belgeyi bulun ve üzerine tıklayın.
- “Edit Document” butonuna tıklayın.
- Gerekli değişiklikleri yapın ve “Update” butonuna tıklayın.
MongoDB Compass ile Performans Analizi
Compass, sorguların performansını analiz eder ve yavaş sorguları tespit eder. Örneğin, bir sorgunun performansını analiz etmek için:
- Sorguyu çalıştırın.
- “Explain” sekmesine tıklayın.
- Sorgunun çalışma süresi, tarama yöntemi ve kullanılan indeksler hakkında bilgi edinin.
Eğer sorgu yavaşsa, Compass size uygun indeks önerileri sunar.
MongoDB Compass ile İndeks Yönetimi
Compass, koleksiyonlar üzerinde indeks oluşturma, silme ve yönetme imkanı sunar. Örneğin, yeni bir indeks oluşturmak için:
- Koleksiyonu seçin.
- “Indexes” sekmesine tıklayın.
- “Create Index” butonuna tıklayın.
- İndeks alanlarını ve türünü belirleyin.
MongoDB Compass’ın Avantajları
- Kullanım Kolaylığı: Grafik arayüzü sayesinde komut satırı bilgisi gerektirmez.
- Veri Görselleştirme: Verileri kolayca görselleştirme ve analiz etme imkanı sunar.
- Performans Analizi: Sorguların performansını analiz eder ve optimizasyon önerileri sunar.
- Platform Bağımsızlık: Windows, macOS ve Linux işletim sistemlerinde çalışır.
Örnek Senaryo: E-Ticaret Veritabanı Analizi
Bir e-ticaret veritabanında, orders
koleksiyonundaki siparişleri analiz etmek istediğinizi varsayalım. Compass ile aşağıdaki adımları izleyebilirsiniz:
Siparişleri Filtreleme: status
alanı “shipped” olan siparişleri bulun.
- Filtre:
{ status: "shipped" }
Toplam Sipariş Tutarını Hesaplama:
- Aggregation Pipeline:
json [ { $match: { status: "shipped" } }, { $group: { _id: null, totalAmount: { $sum: "$amount" } } } ]
Şema Analizi: orders
koleksiyonunun şema yapısını analiz edin.
MongoDB Charts
MongoDB Charts Nedir?
MongoDB Charts, MongoDB veritabanlarındaki verileri görselleştirmek için tasarlanmış bir araçtır. Bu araç, kullanıcıların verilerini interaktif grafiklere ve raporlara dönüştürmesine olanak tanır. MongoDB Charts, hem MongoDB Atlas (bulut tabanlı MongoDB hizmeti) hem de şirket içi MongoDB dağıtımlarıyla entegre çalışabilir.
MongoDB Charts’ın Temel Özellikleri
Veri Görselleştirme:
- Verileri çeşitli grafik türlerinde (çubuk grafik, pasta grafik, çizgi grafik vb.) görselleştirme imkanı sunar.
- Verileri filtreleme ve gruplama özellikleri sayesinde detaylı analizler yapılabilir.
Gerçek Zamanlı Veri Güncellemesi:
- Veritabanındaki değişiklikler anında grafiklere yansıtılır.
Paylaşılabilir Panolar:
- Oluşturulan grafikler, paylaşılabilir panolarda bir araya getirilebilir.
- Panolar, ekip üyeleri veya paydaşlarla kolayca paylaşılabilir.
Entegrasyon:
- MongoDB Atlas ile tam entegre çalışır.
- REST API desteği sayesinde, grafikler başka uygulamalara da gömülebilir.
Kullanım Kolaylığı:
- Sürükle-bırak arayüzü sayesinde, teknik bilgi gerektirmeden grafikler oluşturulabilir.
MongoDB Charts Kurulumu
MongoDB Charts, MongoDB Atlas üzerinden kullanılabildiği gibi, şirket içi MongoDB dağıtımları için de kurulabilir. Atlas üzerinde kullanımı oldukça basittir:
- MongoDB Atlas hesabınıza giriş yapın.
- “Charts” sekmesine tıklayın.
- Charts’ı etkinleştirin ve başlayın.
Şirket içi kullanım için ise MongoDB Charts dokümantasyonunu takip edebilirsiniz.
MongoDB Charts Kullanımı
1. Veri Kaynağı Ekleme
MongoDB Charts’ı kullanmaya başlamak için öncelikle bir veri kaynağı eklemeniz gerekiyor. Veri kaynağı, MongoDB veritabanınızdaki bir koleksiyon olabilir.
- Charts arayüzüne gidin.
- “Data Sources” sekmesine tıklayın.
- “Add Data Source” butonuna tıklayın.
- Bağlantı bilgilerini girerek veri kaynağını ekleyin.
2. Grafik Oluşturma
Veri kaynağı eklendikten sonra, grafik oluşturmaya başlayabilirsiniz. Örneğin, bir sales
koleksiyonundaki satış verilerini görselleştirmek için:
- “Charts” sekmesine gidin.
- “Add Chart” butonuna tıklayın.
- Veri kaynağı olarak
sales
koleksiyonunu seçin. - Grafik türünü seçin (örneğin, çubuk grafik).
- Eksenleri belirleyin:
- X ekseni:
product
- Y ekseni:
totalSales
Grafiği kaydedin.
3. Filtreleme ve Gruplama
Grafikler üzerinde filtreleme ve gruplama işlemleri yapabilirsiniz. Örneğin, sadece belirli bir bölgedeki satışları görüntülemek için:
- Grafik ayarlarına gidin.
- “Filters” sekmesine tıklayın.
- Filtre ekleyin:
{ region: "Europe" }
Benzer şekilde, verileri gruplayarak daha detaylı analizler yapabilirsiniz. Örneğin, satışları ürün kategorisine göre gruplamak için:
- Grafik ayarlarına gidin.
- “Group By” seçeneğini kullanarak
category
alanını seçin.
4. Panolar Oluşturma
Birden fazla grafiği bir araya getirerek panolar oluşturabilirsiniz. Örneğin, satış performansını gösteren bir pano oluşturmak için:
- “Dashboards” sekmesine gidin.
- “Add Dashboard” butonuna tıklayın.
- Pano adını belirleyin ve kaydedin.
- Daha önce oluşturduğunuz grafikleri panele ekleyin.
5. Grafikleri Paylaşma
Oluşturduğunuz grafikleri ve panoları başkalarıyla paylaşabilirsiniz. Paylaşım seçenekleri arasında:
- Public Link: Grafiği herkese açık bir link ile paylaşma.
- Embed: Grafiği bir web sayfasına veya uygulamaya gömme.
MongoDB Charts ile Örnek Senaryo: Satış Analizi
Bir e-ticaret şirketinin sales
koleksiyonundaki verileri analiz etmek istediğinizi varsayalım. Bu koleksiyon, aşağıdaki gibi belgeler içeriyor:
{
"_id": 1,
"product": "Laptop",
"category": "Electronics",
"region": "Europe",
"totalSales": 5000,
"date": "2023-10-01"
}
1. Bölgelere Göre Satışlar
- Grafik Türü: Çubuk Grafik
- X Ekseni:
region
- Y Ekseni:
totalSales
2. Kategorilere Göre Satışlar
- Grafik Türü: Pasta Grafik
- Gruplama:
category
- Değer:
totalSales
3. Zaman İçinde Satış Trendi
- Grafik Türü: Çizgi Grafik
- X Ekseni:
date
- Y Ekseni:
totalSales
MongoDB Charts’ın Avantajları
- Kolay Kullanım: Sürükle-bırak arayüzü sayesinde teknik bilgi gerektirmez.
- Gerçek Zamanlı Veri: Veritabanındaki değişiklikler anında grafiklere yansıtılır.
- Entegrasyon: MongoDB Atlas ve şirket içi MongoDB ile tam uyumlu çalışır.
- Paylaşılabilirlik: Grafikler ve panolar kolayca paylaşılabilir veya gömülebilir.
Kaynakça:
- https://www.mongodb.com/docs/manual/crud/
- https://www.geeksforgeeks.org/mongodb-crud-operations/
- https://www.mongodb.com/docs/manual/core/aggregation-pipeline/
- https://pymongo.readthedocs.io/en/stable/,
- https://www.mongodb.com/docs/manual/core/timeseries-collections/
Hayat her ne kadar zor görünse de, yapabileceğiniz ve başarabileceğiniz bir şey her zaman vardır.
Stephen Hawking
Bir sonraki yazıda görüşmek dileğiyle!”