Takip et

MongoDB CRUD İşlemleri: Üniversite Öğrenci Yönetim Sistemi

Günümüz dijital dünyasında, ister basit bir web uygulaması isterse karmaşık bir kurumsal sistem olsun, her yazılımın temelinde veri yönetimi yatar. Peki, bu verileri nasıl oluşturur, okur, günceller ve sileriz? İşte bu sorunun cevabı, modern veri tabanı yönetiminin kalbi olan CRUD (Create, Read, Update, Delete) işlemlerinde gizlidir. Bu makalede, özellikle esnek yapısıyla dikkat çeken NoSQL veritabanı MongoDB üzerinde, bir üniversite öğrenci yönetim sistemi örneği üzerinden CRUD işlemlerini adım adım, uygulamalı bir şekilde keşfedeceğiz. Bu rehber sayesinde MongoDB ile veri manipülasyonunun inceliklerini sıfırdan öğrenerek projelerinizde rahatlıkla uygulayabileceksiniz.

Veri tabanları, modern uygulamaların bel kemiğini oluşturur ve bunların etkin bir şekilde yönetilmesi, yazılımların performansı, güvenilirliği ve ölçeklenebilirliği için hayati önem taşır. CRUD kısaltması, bir veri tabanındaki temel etkileşimleri ifade eder: Yeni kayıtlar Oluşturma (Create), mevcut kayıtları Okuma (Read), bilgileri Güncelleme (Update) ve eski veya gereksiz kayıtları Silme (Delete). Bu dört temel işlem, bir kullanıcının bir uygulamayla gerçekleştirdiği hemen hemen her etkileşimi kapsar. Örneğin, bir öğrencinin sisteme kaydolması ‘Create’, notlarını kontrol etmesi ‘Read’, adres bilgilerini güncellemesi ‘Update’ ve kaydını sildirmesi ‘Delete’ işlemine karşılık gelir. Dolayısıyla, bu işlemlere hakim olmak, herhangi bir geliştiricinin veri tabanıyla etkili bir şekilde çalışabilmesi için kaçınılmaz bir gerekliliktir. MongoDB gibi NoSQL veritabanları, bu işlemleri belge tabanlı, esnek ve yüksek performanslı bir yaklaşımla ele alarak geliştiricilere büyük kolaylıklar sağlar. Üniversite öğrenci yönetim sistemi gibi bir senaryo, bu CRUD işlemlerinin gerçek dünya kullanımını anlamak için mükemmel bir örnek teşkil eder.

MongoDB ve Belge Tabanlı Veritabanı Yaklaşımı Nedir?

Geleneksel ilişkisel veri tabanlarının aksine (örneğin MySQL, PostgreSQL), MongoDB, NoSQL ailesine ait, belge tabanlı (document-oriented) bir veri tabanıdır. Bu ne anlama geliyor? Şöyle düşünün: İlişkisel veri tabanları veriyi katı, önceden tanımlanmış tablolar ve satırlar halinde saklarken, MongoDB veriyi esnek JSON benzeri belgeler (BSON formatında) halinde depolar. Her belge, bir nesne gibi düşünebilirsiniz ve farklı alanlara sahip olabilir. Bu esneklik, özellikle hızlı değişen ve karmaşık veri yapılarına sahip uygulamalar için muazzam bir avantaj sunar.

MongoDB’nin temel özellikleri ve terminolojisi şunlardır:

  • Belge (Document): MongoDB’deki temel veri birimidir. Alan ve değer çiftlerinden oluşan JSON benzeri yapılardır. Örneğin, bir öğrenci belgesi { "_id": ObjectId("..."), "ad": "Ali", "soyad": "Yılmaz", "numara": "12345", "bolum": "Bilgisayar Mühendisliği" } şeklinde olabilir.
  • Koleksiyon (Collection): Belgelerin gruplandığı yerdir. İlişkisel veri tabanlarındaki tablolara benzer, ancak bir koleksiyondaki belgeler farklı şemalara sahip olabilir (şemasız yapı). Örneğin, ‘ogrenciler’ adında bir koleksiyonumuz olabilir.
  • Veritabanı (Database): Koleksiyonların mantıksal bir kümesidir. Bir MongoDB sunucusu birden fazla veritabanı barındırabilir.
  • Esnek Şema (Flexible Schema): Belki de en büyük farklardan biri budur. MongoDB’de bir koleksiyondaki her belge aynı alanlara sahip olmak zorunda değildir. Bu durum, veri modelinizi zaman içinde kolayca evrimleştirmenize olanak tanır.
  • Yüksek Performans ve Ölçeklenebilirlik: Büyük veri kümeleri ve yüksek trafikli uygulamalar için tasarlanmıştır. Yatay ölçeklenebilirlik (sharding) sayesinde veri tabanınızı birden fazla sunucuya yayarak performansı artırabilirsiniz.

Öğrenci Yönetim Sistemi İçin Basit Bir Şema Nasıl Tasarlanır?

Üniversite öğrenci yönetim sistemi örneğimiz için oldukça basit ama işlevsel bir öğrenci şeması tasarlayacağız. Bu şema, öğrencilerin temel bilgilerini ve aldıkları dersleri içerecek. Esnek şema yapısı sayesinde, ilerleyen zamanlarda öğrenci belgelerine kolayca yeni alanlar ekleyebileceğimizi unutmayalım.


{
  "_id": ObjectId("..."), // Her belge için benzersiz ID, MongoDB tarafından otomatik atanır
  "ogrenciNumarasi": "2023001",
  "ad": "Elif",
  "soyad": "Demir",
  "bolum": "Yazılım Mühendisliği",
  "email": "elif.demir@universite.edu.tr",
  "dogumTarihi": ISODate("2000-05-15T00:00:00Z"),
  "notOrtalamasi": 3.75,
  "aktif": true,
  "aldigiDersler": [
    { "kod": "YS101", "ad": "Veri Yapıları", "kredi": 4 },
    { "kod": "YS102", "ad": "Algoritma Analizi", "kredi": 3 }
  ],
  "kayitTarihi": ISODate("2023-09-01T10:00:00Z")
}
    

Yukarıdaki örnek belge, bir öğrencinin temel bilgilerini, derslerini ve diğer önemli detayları barındırıyor. Gördüğünüz gibi, aldigiDersler alanı bir dizi (array) ve her dizi elemanı da kendi içinde birer belge (nested document) içeriyor. Bu yapı, ilişkisel veri tabanlarında birden çok tablo ve join işlemi gerektirecekken, MongoDB'de tek bir belge içinde kolayca modellenebilir.

Uzman İpucu: MongoDB'de veri modellemesi yaparken, "embedded documents" (iç içe belgeler) ve "references" (referanslar) arasında seçim yapmanız gerekir. Genellikle, bir veri diğerine sıkıca bağlıysa ve birlikte sorgulanıyorsa embedded documents tercih edilir. Eğer veriler birbirinden bağımsız sorgulanıyor veya çok büyükse, referanslar daha uygun olabilir. Öğrencinin aldığı dersler, öğrenciye sıkıca bağlı olduğu için embedded documents kullanımı mantıklıdır.

Öğrenci Verilerini MongoDB'ye Nasıl Ekleriz? (Create İşlemi)

Veri tabanına yeni kayıtlar eklemek, yani "Create" işlemi, CRUD operasyonlarının ilk ve en temel adımıdır. MongoDB'de bu işlemi gerçekleştirmek için genellikle insertOne() ve insertMany() metotlarını kullanırız. Bu metotlar, bir veya birden fazla belgeyi belirtilen bir koleksiyona eklememizi sağlar. Şimdi bu işlemleri üniversite öğrenci yönetim sistemi örneği üzerinden detaylıca inceleyelim.

Tek Bir Öğrenci Kaydı Nasıl Oluşturulur? (insertOne)

Sisteme yeni bir öğrencinin kaydını yapmak istediğimizde, insertOne() metodu imdadımıza yetişir. Bu metot, tek bir belge (JSON nesnesi) alır ve onu hedef koleksiyona ekler. MongoDB, eklenen her belgeye otomatik olarak benzersiz bir _id alanı atar. Eğer belge içinde manuel olarak bir _id belirtmezsek, bu ID otomatik olarak oluşturulur.


// Node.js ve MongoDB Driver kullanarak örnek
const { MongoClient } = require('mongodb');

async function createOneStudent() {
  const uri = "mongodb://localhost:27017"; // MongoDB bağlantı URI'si
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB"); // universiteDB veritabanı
    const ogrenciler = database.collection("ogrenciler"); // ogrenciler koleksiyonu

    const yeniOgrenci = {
      ogrenciNumarasi: "2023005",
      ad: "Ayşe",
      soyad: "Yıldız",
      bolum: "Pazarlama",
      email: "ayse.yildiz@universite.edu.tr",
      dogumTarihi: new Date("2001-11-20"),
      notOrtalamasi: 3.20,
      aktif: true,
      aldigiDersler: [
        { kod: "PZ101", ad: "Pazarlamaya Giriş", kredi: 3 }
      ],
      kayitTarihi: new Date()
    };

    const result = await ogrenciler.insertOne(yeniOgrenci);
    console.log(Yeni öğrenci eklendi: ID - ${result.insertedId}); // Yeni öğrencinin ID'si
  } finally {
    await client.close();
  }
}

createOneStudent();
    

Bu kod bloğu, universiteDB veri tabanındaki ogrenciler koleksiyonuna "Ayşe Yıldız" adlı yeni bir öğrenci kaydı ekler. İşlem başarılı olduğunda, eklenen öğrencinin otomatik olarak oluşturulan _id değeri konsola yazdırılır. Bu yöntem, tekil veri girişi gereken durumlarda oldukça kullanışlıdır, örneğin bir öğrencinin kayıt formunu doldurup gönderdiğinde.

Birden Fazla Öğrenci Kaydını Aynı Anda Nasıl Yaparız? (insertMany)

Bazen birden fazla öğrenciyi aynı anda veri tabanına eklememiz gerekebilir, örneğin bir dönem başında toplu öğrenci kayıtları yapıldığında. Bu tür durumlar için insertMany() metodu idealdir. Bu metot, belge nesnelerinden oluşan bir dizi alır ve tümünü tek bir işlemde koleksiyona ekler.


const { MongoClient } = require('mongodb');

async function createManyStudents() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    const yeniOgrenciler = [
      {
        ogrenciNumarasi: "2023006",
        ad: "Burak",
        soyad: "Can",
        bolum: "İletişim",
        email: "burak.can@universite.edu.tr",
        dogumTarihi: new Date("2002-01-10"),
        notOrtalamasi: 2.90,
        aktif: true,
        aldigiDersler: [{ kod: "İL101", ad: "İletişim Kuramları", kredi: 3 }],
        kayitTarihi: new Date()
      },
      {
        ogrenciNumarasi: "2023007",
        ad: "Zeynep",
        soyad: "Kara",
        bolum: "Hukuk",
        email: "zeynep.kara@universite.edu.tr",
        dogumTarihi: new Date("2000-08-25"),
        notOrtalamasi: 3.50,
        aktif: true,
        aldigiDersler: [{ kod: "HK101", ad: "Hukuka Giriş", kredi: 5 }],
        kayitTarihi: new Date()
      }
    ];

    const result = await ogrenciler.insertMany(yeniOgrenciler);
    console.log(${result.insertedCount} adet öğrenci başarıyla eklendi.);
    console.log('Eklenen öğrenci ID\'leri:', result.insertedIds);
  } finally {
    await client.close();
  }
}

createManyStudents();
    

Bu örnekte, bir dizi içinde iki yeni öğrenci belgesi tanımlandı ve insertMany() ile tek seferde ogrenciler koleksiyonuna eklendi. İşlem sonunda, kaç öğrencinin eklendiğini ve her birinin benzersiz _id değerlerini konsolda görebiliriz. Bu toplu ekleme operasyonu, özellikle büyük veri setlerinin aktarımı veya ilk kurulum aşamalarında zaman tasarrufu sağlar.

Uzman İpucu: insertMany() metoduna opsiyonel olarak ordered: false parametresi geçebilirsiniz. Bu, bir belgenin eklenmesi başarısız olsa bile diğer belgelerin ekleme işleminin devam etmesini sağlar. Varsayılan olarak ordered: true'dur, yani bir hata durumunda tüm işlem durdurulur.

Create işlemleri, bir veri tabanının hayat döngüsündeki ilk adımdır. Doğru ve verimli bir şekilde yapıldığında, veri tabanınızın sağlam temeller üzerine kurulmasını sağlar. Şimdi, eklediğimiz bu verilere nasıl ulaşacağımızı inceleyelim.

MongoDB'de Öğrenci Bilgilerine Nasıl Ulaşırız? (Read İşlemi)

Veri tabanına eklediğimiz bilgileri okumak, yani "Read" işlemi, en sık kullanılan CRUD operasyonlarından biridir. Öğrenci yönetim sisteminde, belirli bir öğrencinin bilgilerine ulaşmaktan, belirli kriterlere uyan tüm öğrencilerin listesini almaya kadar birçok senaryoda okuma işlemleri yaparız. MongoDB, bu ihtiyacı karşılamak için güçlü sorgu yetenekleri sunar ve findOne() ile find() metotları temel araçlarımızdır.

Tek Bir Öğrencinin Bilgilerini Nasıl Getiririz? (findOne)

Belirli bir öğrencinin detaylarına, örneğin öğrenci numarasına göre ulaşmak istediğimizde findOne() metodu kullanılır. Bu metot, sorgu kriterleriyle eşleşen ilk belgeyi döndürür. Eğer eşleşen bir belge bulunamazsa null döner.


const { MongoClient } = require('mongodb');

async function readOneStudent() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    // Öğrenci numarasına göre arama
    const ogrenci = await ogrenciler.findOne({ ogrenciNumarasi: "2023005" });

    if (ogrenci) {
      console.log('Bulunan Öğrenci:', ogrenci);
    } else {
      console.log('Belirtilen öğrenci numarasına sahip öğrenci bulunamadı.');
    }
  } finally {
    await client.close();
  }
}

readOneStudent();
    

Yukarıdaki örnekte, ogrenciNumarasi: "2023005" kriteriyle bir arama yapılıyor. Bu, bir öğrencinin profil sayfasını veya detaylarını görüntülemek için sıkça kullanılan bir senaryodur.

Belirli Kriterlere Uyan Birden Fazla Öğrenciyi Nasıl Listeleriz? (find)

Bir dersi alan tüm öğrencileri, belirli bir bölümdeki öğrencileri veya not ortalaması belli bir değerin üzerinde olan öğrencileri listelemek istediğimizde find() metodunu kullanırız. find(), sorgu kriterleriyle eşleşen tüm belgeleri içeren bir Cursor (imleç) döndürür. Bu imleç üzerinde toArray() veya forEach() gibi metotlarla döngü yapabiliriz.


const { MongoClient } = require('mongodb');

async function readManyStudents() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    // Not ortalaması 3.0'ın üzerinde olan ve "Yazılım Mühendisliği" bölümündeki öğrencileri listeleme
    const query = {
      notOrtalamasi: { $gt: 3.0 }, // greater than (büyük)
      bolum: "Yazılım Mühendisliği"
    };

    const ogrencilerListesi = await ogrenciler.find(query).toArray();

    if (ogrencilerListesi.length > 0) {
      console.log('Not ortalaması 3.0 üzeri ve Yazılım Mühendisliği bölümündeki öğrenciler:');
      ogrencilerListesi.forEach(ogrenci => {
        console.log(- ${ogrenci.ad} ${ogrenci.soyad} (${ogrenci.ogrenciNumarasi}) - Not Ort: ${ogrenci.notOrtalamasi});
      });
    } else {
      console.log('Belirtilen kriterlere uyan öğrenci bulunamadı.');
    }
  } finally {
    await client.close();
  }
}

readManyStudents();
    

Bu örnekte, $gt (greater than) operatörü kullanılarak not ortalaması 3.0'dan büyük olan öğrenciler filtreleniyor. Ayrıca, bolum alanı da sorguya dahil edilerek iki kriterin de karşılanması sağlanıyor. MongoDB'nin zengin sorgu operatörleri seti, çok çeşitli ve karmaşık sorguları kolayca oluşturmanıza olanak tanır:

  • $eq: Eşit (varsayılan)
  • $ne: Eşit değil
  • $gt: Büyüktür
  • $gte: Büyük veya eşittir
  • $lt: Küçüktür
  • $lte: Küçük veya eşittir
  • $in: Belirtilen dizideki değerlerden birine eşittir
  • $nin: Belirtilen dizideki değerlerden hiçbirine eşit değildir
  • $and, $or, $not, $nor: Mantıksal operatörler

Sorgu Sonuçlarını Özelleştirme: Projektion ve Sıralama

Bazen bir belgenin tüm alanlarına ihtiyacımız olmaz; sadece belirli bilgileri görmek isteyebiliriz. Bu durumda "Projektion" kullanırız. Ayrıca, sonuçları belirli bir alana göre sıralamak (sort()) veya belirli bir sayıda sonuçla sınırlamak (limit()) da mümkündür.


const { MongoClient } = require('mongodb');

async function readProjectionAndSort() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    // Tüm öğrencileri not ortalamasına göre azalan sırada listele, sadece ad, soyad ve not ortalaması alanlarını göster
    const query = {}; // Tüm belgeler
    const projection = { ad: 1, soyad: 1, notOrtalamasi: 1, _id: 0 }; // 1: göster, 0: gösterme
    const sort = { notOrtalamasi: -1 }; // -1: azalan, 1: artan

    const enBasariliOgrenciler = await ogrenciler.find(query)
                                               .project(projection)
                                               .sort(sort)
                                               .limit(5) // İlk 5 öğrenciyi göster
                                               .toArray();

    console.log('En Başarılı 5 Öğrenci (Not Ortalamasına Göre Azalan Sıra):', enBasariliOgrenciler);
  } finally {
    await client.close();
  }
}

readProjectionAndSort();
    

Bu örnek, tüm öğrencileri not ortalamalarına göre azalan sırada sıralar ve yalnızca ad, soyad ve notOrtalamasi alanlarını gösterir (_id alanı hariç tutulmuştur). Sonuçlar limit(5) ile ilk 5 öğrenciyle sınırlandırılır. Bu tür özelleştirmeler, uygulamanızın performansını artırır çünkü veri tabanından gereksiz veri transferi yapmasını engeller.

Uzman İpucu: Sorgularınızı optimize etmek için doğru indeksleme stratejileri kullanmak performansı önemli ölçüde artırır. Sıkça sorguladığınız alanlara (örneğin ogrenciNumarasi, bolum, notOrtalamasi) indeks eklemeyi düşünebilirsiniz.

Read işlemleri, uygulamaların kullanıcıya bilgi sunmasının temel yoludur. Etkili sorgular yazarak, kullanıcılarınızın ihtiyaç duyduğu verilere hızlı ve doğru bir şekilde ulaşmasını sağlayabilirsiniz.

Mevcut Öğrenci Verilerini Güncelleme Sanatı (Update İşlemi)

Veri tabanındaki mevcut bilgileri değiştirmek, yani "Update" işlemi, bir uygulamanın dinamizmini sağlayan kritik bir CRUD operasyonudur. Öğrenci yönetim sistemimizde bir öğrencinin not ortalamasının değişmesi, adres bilgisinin güncellenmesi veya kayıtlı derslerinin yenilenmesi gibi durumlar, güncelleme işlemlerini gerektirir. MongoDB, bu tür senaryolar için çeşitli ve esnek güncelleme metotları ile operatörleri sunar: updateOne(), updateMany() ve replaceOne().

Tek Bir Öğrenci Bilgisini Nasıl Güncelleriz? (updateOne)

Belirli bir öğrencinin tek bir veya birden fazla alanını güncellemek istediğimizde updateOne() metodu kullanılır. Bu metot iki ana argüman alır: birincisi, güncellenecek belgeyi bulan sorgu filtresi; ikincisi ise, uygulanacak güncelleme operasyonlarını içeren bir belge (genellikle güncelleme operatörleri ile birlikte). Örneğin, bir öğrencinin not ortalamasını veya e-posta adresini değiştirebiliriz.


const { MongoClient } = require('mongodb');

async function updateOneStudent() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    const filter = { ogrenciNumarasi: "2023005" }; // Güncellenecek öğrenciyi bulan filtre
    const updateDoc = {
      $set: { // $set operatörü, belirtilen alanın değerini ayarlar
        notOrtalamasi: 3.85,
        email: "ayse.yildiz.yeni@universite.edu.tr"
      }
    };

    const result = await ogrenciler.updateOne(filter, updateDoc);
    console.log(${result.matchedCount} adet belge eşleşti, ${result.modifiedCount} adet belge güncellendi.);

    if (result.modifiedCount > 0) {
        console.log('Öğrenci bilgileri başarıyla güncellendi.');
    } else {
        console.log('Öğrenci bulunamadı veya bilgi değişmedi.');
    }
  } finally {
    await client.close();
  }
}

updateOneStudent();
    

Yukarıdaki örnekte, "2023005" numaralı öğrencinin notOrtalamasi ve email alanları $set operatörü kullanılarak güncelleniyor. $set, bir alanın değerini ayarlamak veya mevcut olmayan bir alanı eklemek için en yaygın kullanılan operatördür. matchedCount eşleşen belge sayısını, modifiedCount ise gerçekten güncellenen belge sayısını gösterir.

Birden Fazla Öğrencinin Bilgilerini Toplu Nasıl Güncelleriz? (updateMany)

Bazen birden fazla belgeyi aynı anda güncellememiz gerekebilir. Örneğin, bir bölümdeki tüm öğrencilerin "aktif" durumunu değiştirmek veya belirli bir derste başarısız olan tüm öğrencilerin not ortalamasını ayarlamak gibi. updateMany() metodu, sorgu filtresiyle eşleşen tüm belgeleri günceller.


const { MongoClient } = require('mongodb');

async function updateManyStudents() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    // Tüm "Pazarlama" bölümü öğrencilerinin not ortalamasını 0.1 puan artırma
    const filter = { bolum: "Pazarlama" };
    const updateDoc = {
      $inc: { // $inc operatörü, bir sayısal alanı belirli bir değer kadar artırır/azaltır
        notOrtalamasi: 0.1
      }
    };

    const result = await ogrenciler.updateMany(filter, updateDoc);
    console.log(${result.matchedCount} adet belge eşleşti, ${result.modifiedCount} adet belge güncellendi.);

    if (result.modifiedCount > 0) {
        console.log('Pazarlama bölümündeki öğrencilerin not ortalamaları başarıyla güncellendi.');
    } else {
        console.log('Pazarlama bölümünde öğrenci bulunamadı veya not ortalamaları zaten en yüksek seviyede.');
    }
  } finally {
    await client.close();
  }
}

updateManyStudents();
    

Bu kod, bolum: "Pazarlama" kriterine uyan tüm öğrencilerin notOrtalamasi alanını $inc operatörü ile 0.1 puan artırır. $inc, sayısal alanları atomik bir şekilde (yani, aynı anda başka bir işlem olsa bile doğru sonucu garanti ederek) artırmak veya azaltmak için idealdir.

Bir Belgeyi Tamamen Değiştirmek: replaceOne()

Bazen bir belgenin sadece birkaç alanını güncellemek yerine, onu tamamen yeni bir belgeyle değiştirmek isteyebiliriz. replaceOne() metodu bu iş için kullanılır. Bu metot, sorgu filtresiyle eşleşen ilk belgeyi bulur ve onu sağlanan yeni belgeyle değiştirir. Ancak _id alanı hariç, eski belgedeki tüm alanlar yenisiyle değişir. Eğer yeni belgede eski bir alan yoksa, o alan silinir; yeni bir alan varsa, o alan eklenir.


const { MongoClient } = require('mongodb');
const { ObjectId } = require('mongodb'); // ObjectId'ı import etmeyi unutmayın

async function replaceOneStudent() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    // Örneğin, belirli bir _id'ye sahip öğrenciyi tamamen farklı bilgilerle değiştirme
    // NOT: Gerçek bir senaryoda _id'yi dinamik olarak almanız gerekir.
    const filter = { _id: new ObjectId("65f9a7b3c6d7e8f9a0b1c2d3") }; // Mevcut bir öğrencinin _id'si
    const replacementDoc = {
      ogrenciNumarasi: "2023008",
      ad: "Mehmet",
      soyad: "Ak",
      bolum: "Edebiyat",
      email: "mehmet.ak@universite.edu.tr",
      dogumTarihi: new Date("2000-03-10"),
      notOrtalamasi: 2.50,
      aktif: true,
      aldigiDersler: [{ kod: "ED101", ad: "Türk Edebiyatı", kredi: 4 }],
      kayitTarihi: new Date("2023-09-01T10:00:00Z") // Mevcut bir tarihten farklı olabilir
    };

    const result = await ogrenciler.replaceOne(filter, replacementDoc);
    console.log(${result.matchedCount} adet belge eşleşti, ${result.modifiedCount} adet belge değiştirildi.);

    if (result.modifiedCount > 0) {
        console.log('Öğrenci belgesi tamamen değiştirildi.');
    } else {
        console.log('Öğrenci bulunamadı veya zaten aynıydı.');
    }
  } finally {
    await client.close();
  }
}

// replaceOneStudent(); // Bu fonksiyonu çalıştırmadan önce geçerli bir ObjectId ile değiştirmeyi unutmayın!
    

Bu örnek, belirli bir _id'ye sahip öğrenciyi replacementDoc ile tamamen değiştirir. Eski belgedeki _id korunur, ancak diğer tüm alanlar yeni belgedeki değerlerle değişir. Bu metot, genellikle bir belgenin yapısı kökten değiştiğinde veya eski verilerin tamamen yeniyle değiştirilmesi gerektiğinde tercih edilir.

Uzman İpucu: Güncelleme operatörleri ($set, $inc, $push, $pull vb.) verimli ve atomik işlemler sağlar. Bu operatörleri kullanarak sadece ilgili alanları güncelleyebilir, böylece veri tutarlılığını artırabilir ve performansı optimize edebilirsiniz. Tüm belgeyi güncellemek yerine (replaceOne), genellikle operatörlerle parça parça güncellemek (updateOne/updateMany) daha iyi bir yaklaşımdır.

Güncelleme işlemleri, veri tabanınızın canlı kalmasını ve değişen ihtiyaçlara adaptasyonunu sağlar. Doğru operatörleri ve metotları seçerek, verilerinizi verimli ve güvenli bir şekilde yönetebilirsiniz.

Gereksiz Öğrenci Kayıtlarını Güvenle Silme (Delete İşlemi)

Veri tabanındaki gereksiz veya eski kayıtları silmek, yani "Delete" işlemi, CRUD operasyonlarının son aşamasıdır. Öğrenci yönetim sisteminde, mezun olan öğrencilerin kayıtlarını arşivlemek veya kaydı iptal edilen öğrencilerin bilgilerini sistemden tamamen kaldırmak gerekebilir. MongoDB, bu işlemleri gerçekleştirmek için deleteOne() ve deleteMany() metotlarını sunar.

Tek Bir Öğrenci Kaydını Nasıl Sileriz? (deleteOne)

Belirli bir öğrencinin kaydını silmek istediğimizde deleteOne() metodu kullanılır. Bu metot, sorgu filtresiyle eşleşen *ilk* belgeyi siler. Bu genellikle, benzersiz bir tanımlayıcı (örneğin _id veya ogrenciNumarasi) kullanarak belirli bir öğrenciyi hedeflediğimizde tercih edilir.


const { MongoClient } = require('mongodb');

async function deleteOneStudent() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    const filter = { ogrenciNumarasi: "2023007" }; // Silinecek öğrenciyi bulan filtre

    const result = await ogrenciler.deleteOne(filter);
    console.log(${result.deletedCount} adet belge silindi.);

    if (result.deletedCount > 0) {
        console.log('Öğrenci kaydı başarıyla silindi.');
    } else {
        console.log('Belirtilen öğrenci numarasına sahip öğrenci bulunamadı.');
    }
  } finally {
    await client.close();
  }
}

deleteOneStudent();
    

Yukarıdaki kod, "2023007" numaralı öğrencinin kaydını ogrenciler koleksiyonundan siler. deletedCount özelliği, silinen belge sayısını gösterir. Bu, genellikle bir kullanıcının kendi hesabını kapatması veya yöneticinin tekil bir kaydı kaldırması gibi durumlarda kullanılır.

Birden Fazla Öğrenci Kaydını Toplu Nasıl Sileriz? (deleteMany)

Bazen belirli kriterlere uyan birden fazla öğrenci kaydını aynı anda silmemiz gerekebilir. Örneğin, belirli bir tarihten önce kayıt olan ve artık aktif olmayan tüm mezun öğrencileri silmek gibi. deleteMany() metodu, sorgu filtresiyle eşleşen tüm belgeleri siler.


const { MongoClient } = require('mongodb');

async function deleteManyStudents() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db("universiteDB");
    const ogrenciler = database.collection("ogrenciler");

    // Not ortalaması 2.0'ın altında olan ve pasif durumdaki tüm öğrencileri silme
    const filter = {
      notOrtalamasi: { $lt: 2.0 },
      aktif: false
    };

    const result = await ogrenciler.deleteMany(filter);
    console.log(${result.deletedCount} adet belge silindi.);

    if (result.deletedCount > 0) {
        console.log('Kriterlere uyan öğrenciler başarıyla silindi.');
    } else {
        console.log('Silinecek öğrenci bulunamadı.');
    }
  } finally {
    await client.close();
  }
}

// deleteManyStudents(); // Bu fonksiyonu dikkatli kullanın, geri dönüşü yoktur!
    

Bu örnekte, not ortalaması 2.0'ın altında olan ve aktif: false durumundaki tüm öğrencileri silen bir filtre tanımlanıyor. deleteMany() bu kriterlere uyan tüm kayıtları veri tabanından kaldırır. Uyarı: deleteMany() ile yapılan işlemler geri alınamaz. Bu nedenle, filtreleme kriterlerinizi çok dikkatli belirlemeniz kritik önem taşır. Yanlış bir filtre, istenmeyen veri kayıplarına yol açabilir.

Uzman İpucu: Veri silme işlemleri geri döndürülemez olduğundan, üretim ortamlarında bu işlemleri gerçekleştirirken son derece dikkatli olun. Alternatif olarak, silmek yerine belgeleri "pasif" (aktif: false) olarak işaretlemek veya ayrı bir "arşiv" koleksiyonuna taşımak gibi yumuşak silme (soft delete) stratejileri kullanmayı düşünebilirsiniz. Bu, verileri gerektiğinde geri kurtarma esnekliği sağlar.

Delete işlemleri, veri tabanınızın temiz ve yönetilebilir kalmasını sağlar. Ancak, bu işlemlerin hassasiyeti göz önüne alındığında, güvenlik önlemleri ve alternatif stratejiler her zaman akılda tutulmalıdır. Şimdi, bu CRUD işlemlerini daha verimli hale getirmek için ileri düzey ipuçlarına ve mobil uyumluluk konusuna göz atalım.

MongoDB Performansı İçin İleri Düzey İpuçları ve En İyi Uygulamalar

CRUD operasyonlarını öğrenmek, MongoDB ile çalışmanın ilk adımıdır. Ancak gerçek dünya uygulamalarında, veritabanı performansını optimize etmek ve güvenliği sağlamak büyük önem taşır. İşte bu noktada ileri düzey ipuçları ve en iyi uygulamalar devreye girer. Bu bölümde, veritabanınızın daha hızlı, daha güvenli ve daha yönetilebilir olmasına yardımcı olacak bazı önemli stratejilere değineceğiz.

İndeksleme Stratejileri: Sorguları Hızlandırmanın Sırrı

Bir kitapta belirli bir konuyu bulmak için fihrist kullanmak gibidir indeksleme. MongoDB'de indeksler, sorguların hızını önemli ölçüde artırır. Bir sorgu çalıştırıldığında, MongoDB tüm koleksiyonu taramak yerine (full table scan), indeksi kullanarak doğrudan eşleşen belgelere ulaşabilir. Bu, özellikle büyük koleksiyonlarda performansı katlar.

  • Tek Alan İndeksleri: Sıkça sorguladığınız veya sıraladığınız alanlar için oluşturulur. Örneğin, ogrenciNumarasi veya bolum.
    
    await ogrenciler.createIndex({ ogrenciNumarasi: 1 }); // 1: artan sıra
    await ogrenciler.createIndex({ bolum: 1 });
                

  • Bileşik İndeksler: Birden fazla alan üzerinde sorgu yaptığınızda faydalıdır. İndeksleme sırası önemlidir. Örneğin, hem bölüm hem de not ortalamasına göre sorgu yapıyorsanız:
    
    await ogrenciler.createIndex({ bolum: 1, notOrtalamasi: -1 }); // Bölüme göre artan, not ortalamasına göre azalan
                

  • Benzersiz İndeksler (Unique Indexes): Belirli bir alanın değerinin koleksiyon içinde benzersiz olmasını sağlar. Örneğin, her öğrencinin sadece bir ogrenciNumarasi olmalı:
    
    await ogrenciler.createIndex({ ogrenciNumarasi: 1 }, { unique: true });
                

Uzman İpucu: Çok fazla indeks oluşturmak yazma (Create, Update, Delete) işlemlerini yavaşlatabilir çünkü her yazma işleminde indekslerin de güncellenmesi gerekir. Bu nedenle, yalnızca kritik sorgular için indeksler oluşturmak ve indekslerin performansını düzenli olarak izlemek önemlidir. MongoDB'nin explain() metodunu kullanarak sorgularınızın indeksleri nasıl kullandığını analiz edebilirsiniz.

Veri Modellemesi: Embedded vs. Referans Yaklaşımı

MongoDB'de veri modellemesi, uygulamanızın performansı ve esnekliği üzerinde büyük etkiye sahiptir. İki ana yaklaşım vardır:

  1. Embedded Documents (İç İçe Belgeler): İlgili veriler tek bir belgede saklanır. Bu, okuma performansını artırır çünkü tek bir sorguyla tüm ilgili verilere ulaşılır (join'lere gerek kalmaz). Öğrencinin aldığı dersler veya adres bilgileri gibi, ana belgeye ait ve sıkça birlikte sorgulanan veriler için idealdir.
    
    // Öğrencinin dersleri doğrudan belge içinde
    {
      "ogrenciNumarasi": "2023001",
      "ad": "Elif",
      "aldigiDersler": [
        { "kod": "YS101", "ad": "Veri Yapıları" }
      ]
    }
                

  2. References (Referanslar): Belgeler arasında bağlantı kurmak için bir belgede diğerinin _id'si saklanır. Bu, belgeler birbirinden bağımsız sorgulandığında, ilişkisel veri tabanlarındaki join'lere benzer işlemler (ancak uygulama tarafında yapılır) gerektiğinde veya iç içe veriler çok büyük olduğunda kullanılır. Örneğin, fakülte bilgisi ayrı bir koleksiyonda tutulabilir ve öğrenci belgesi sadece fakültenin _id'sini içerebilir.
    
    // Öğrencinin fakülte bilgisi başka bir koleksiyona referansla
    {
      "ogrenciNumarasi": "2023001",
      "ad": "Elif",
      "fakulteId": ObjectId("...ID_OF_FACULTY...")
    }
                

Doğru modelleme, uygulamanızın veri erişim desenlerine göre seçilmelidir. Hem okuma hem de yazma maliyetlerini dengelemek önemlidir.

Aggregasyon Framework'e Kısa Bir Bakış

Karmaşık veri analizi ve raporlama ihtiyaçlarınız olduğunda MongoDB'nin Aggregation Framework'ü devreye girer. Bu güçlü araç, verileri dönüştürmenize, gruplandırmanıza, filtrelemenize ve analiz etmenize olanak tanır. Örneğin, bir bölümdeki öğrencilerin ortalama not ortalamasını bulmak, en çok ders alan öğrencileri listelemek gibi işlemler bu framework ile kolayca yapılabilir. Agrege pipe'ları, veriyi bir dizi işlemden geçirerek istediğiniz sonuca ulaşmanızı sağlar.


// Örnek: Her bölümdeki öğrencilerin ortalama not ortalamasını hesaplama
await ogrenciler.aggregate([
  {
    $group: {
      _id: "$bolum", // Bölüme göre grupla
      ortalamaNot: { $avg: "$notOrtalamasi" }, // Not ortalamasının ortalamasını al
      toplamOgrenci: { $sum: 1 } // Her bölümdeki öğrenci sayısını say
    }
  },
  {
    $sort: { ortalamaNot: -1 } // Ortalama nota göre azalan sırada sırala
  }
]).toArray();
    

Güvenlik Önerileri

Veri güvenliği her zaman öncelikli olmalıdır:

  • Erişim Kontrolü (Authentication/Authorization): Kullanıcı adı/şifre veya sertifikalarla erişimi kısıtlayın. Rol tabanlı erişim kontrolü (RBAC) kullanarak her kullanıcının sadece ihtiyacı olan verilere erişmesini sağlayın.
  • Şifreleme (Encryption): Hassas verileri (örneğin e-posta, kişisel bilgiler) disk üzerinde veya transfer sırasında şifreleyin (TLS/SSL).
  • Ağ Güvenliği: MongoDB sunucularınıza yalnızca güvenli ağlardan (VPN, özel VPC'ler) erişime izin verin. Varsayılan portu değiştirmeyi ve güvenlik duvarı kullanmayı unutmayın.
  • Yedekleme (Backups): Veri kaybını önlemek için düzenli ve otomatik yedeklemeler alın.

Mobil Uygulama Uyumlu Tasarım: Medya Sorguları ile Akıllı Çözümler

Günümüzde kullanıcıların büyük bir kısmı web sitelerine ve uygulamalara mobil cihazlar üzerinden erişiyor. Bu nedenle, hazırladığımız HTML içeriğinin mobil cihazlarda da düzgün ve kullanıcı dostu görünmesini sağlamak kritik öneme sahiptir. Bu bölümde, CSS medya sorgularını (Media Queries) kullanarak HTML içeriğimizi farklı ekran boyutlarına nasıl adapte edebileceğimize dair örnekler sunacağız.

CSS Medya Sorguları Nasıl Kullanılır?

Medya sorguları, CSS kurallarını belirli koşullara (örneğin ekran genişliği, cihaz tipi) bağlı olarak uygulamamızı sağlar. Bu sayede, farklı cihazlarda farklı stil tanımları yaparak responsive (duyarlı) bir tasarım oluşturabiliriz. En yaygın kullanım alanı, ekran genişliğine göre elementlerin boyutunu, düzenini veya görünürlüğünü değiştirmektir.


/* Genel stil tanımları (masaüstü için optimize edilmiş olabilir) */
body {
    font-size: 16px;
    margin: 20px auto;
    max-width: 900px;
}

h2 {
    font-size: 2.2em;
}

/* 768px veya daha küçük ekranlar için stil kuralları */
@media (max-width: 768px) {
    body {
        margin: 15px; /* Yan boşlukları azalt */
        max-width: 100%; /* Tam genişlik kullan */
        font-size: 14px; /* Yazı tipini küçült */
    }

    h2 {
        font-size: 1.8em; /* Başlık boyutunu küçült */
    }

    p {
        text-align: left; /* Mobil cihazlarda daha rahat okunabilir */
    }

    /* Tabloların mobil uyumlu hale getirilmesi örneği */
    table, thead, tbody, th, td, tr {
        display: block; /* Tüm tablo elemanlarını blok seviyesinde göster */
    }

    thead tr {
        position: absolute; /* Başlık satırını gizle */
        top: -9999px;
        left: -9999px;
    }

    tr {
        border: 1px solid #ccc;
        margin-bottom: 10px;
    }

    td {
        border: none; /* Kenarlıklarını kaldır */
        border-bottom: 1px solid #eee; /* Alt kenarlık ekle */
        position: relative;
        padding-left: 50%; /* İçeriği sağa kaydır */
        text-align: right; /* Metni sağa hizala */
    }

    td:before {
        position: absolute;
        top: 6px;
        left: 6px;
        width: 45%;
        padding-right: 10px;
        white-space: nowrap;
        text-align: left;
        font-weight: bold;
        color: #0056b3;
    }
    /* Her sütun için özel başlıklar */
    td:nth-of-type(1):before { content: "Özellik"; }
    td:nth-of-type(2):before { content: "Açıklama"; }
}

/* 480px veya daha küçük ekranlar için ek stil kuralları (daha küçük mobil cihazlar) */
@media (max-width: 480px) {
    h2 {
        font-size: 1.5em;
    }
    .tip {
        padding: 10px 15px;
        font-size: 0.9em;
    }
}
    

Yukarıdaki CSS kodu,