27 Ağustos 2012 Pazartesi

MongoDB Mimarisi ve Örnek Kodlar

MongoDB kurulumundan bahsetmiştik.

Şimdi genel olarak biraz mimarisinden yapısal özelliklerinden NOSQL olmasının getirdiği kazançlardan belki de kayıplardan bahsedelim.

Sonunda da notlarımızı tutabileceğimiz belki de küçük bir not defteri gibi bir proje yapalım.

NOSQL database yapısından bahsederek başlayalım. Aslında normalize edilmiş ilişkisel veritabanı modelinin analiz yapılması için denormalize edip kullandığımızda kendimiz nosql yapıda kullanmış oluyoruz.

İlişkiler arası bağlantılar ve benzeri karmaşıklık seviyesi azaltıldığı, dosya yazıp okuma gibi basit bir sistemle kayıt tuttuğu gibi sebeplerden dolayı NOSQL database yapıları, bilinen DB sistemlerine göre performans ve maliyet odaklı oluyorlar.

Dünyada bilinen diğer belgeye dayalı veritabanı örnekleri olarak Neo4J, BigTable, Cassandra, RavenDBCouchDB sıralanabilir.

İlişkisel veritabanı ile MongoDB'yi karşılaştırırsak. MongoDB JSON objeler üzerine DB mimarisi kuran bir yapıdadır. Bilinen ilişkisel veri tabanları örneklerinde tüm veri yapıları ilişkiler ile takip edilir. Girilen her veri aslında bir önceki veriye bağlanarak takiplenir.

Sıralı ve birbirine her noktadan bağlantılı satır satır girilen veri yerine, JSON objeleri halinde bir dökümanda tutulan serialize edilmiş halde tutar MongoDB.

MYSQL üzerinde bir tablomuz olduğunu düşünelim, tabloya yeni bir veri ekleyeceğiz. "Cinsiyet" diye bir veri sahası ekledik ve ilk 5 satır için bu değerin "E" olmasını için gereken SQL sorgusunu yazdık.

İlk 5 satırdan sonraki tüm veriler için DB üzerindeki alana "null" değer ile kaydetmiş olur.

Aslında olmayan verinin DB üzerinde olmadığına dair işaret verisi tutuluyor.
(null veri tutmayı engellemeye çalışmalıdır örnek amaçlı anlatılmıştır.)

MongoDB'de veri şemasında daha önceden "Cinsiyet" diye bir alan olmadığı halde, yeni verilerin birinde "Cinsiyet=E" şeklinde veri girebiliriz. Sadece o veri için "Cinsiyet" verisi tutulur diğer verilerde herhangi bir değişikliğe gerek yoktur. Hem gereksiz veri (null gibi) tutulmuyor, hem de şema değişiklerinin uygulanması için fazladan bir işlem yapmamıza gerek yoktur. Tutulan verinin büyüklüğü performans ile doğrudan alakalı olduğu için NOSQL mimarilerde saha tanımlamalarında olabildiğince kısa isimler kullanılması öneriliyor.
Örneğin "CreateDate" yerine "cd" yazmak gibi. Okunabilirliği azaltan yazılım geliştiren için sıkıntılı bir durumu vardır.

Biraz da kodlayalım...

Git üzerindeki projemizde, başlık ve içerik bilgisi girip bunları kaydettikten sonra listeyen basit bir projeyi anlatalım.

Tek bir sayfa üzerinde yeni veri girişi için alanlar ve eski verileri listeyelim, yeni veri girişini de aynı sayfaya post yaparak DB'ye kaydedelim.

Post diye bir tanımlama yapalım.
function post(data, id) {
    this.id = id;
    this.baslik = String(data.baslik) || "Başlık Tanımlanmadı";
    this.icerik = String(data.icerik) || "İçerik Tanımlanmadı";
    this.created_at = new Date();
}
module.exports = post;
Veri saklama şemamız bu şekilde olsun. Server.js dosyamızda daha önceki örnekler gibi 
basit bir yapı vardır. db.save ve db.findAll ile işlemlerimiz yapalım.

DB işlemlerini kısaca toplarladığımız DB.js dosyası bir kaç farklı prototype
içermektedir.

DB ile bağlantı kurabilmek için,
DB = function(host, port) {
    this.server = new Server(host, port, { auto_reconnect: true });
    this.db = new Db('nodejstr-blog', this.server);
    this.db.open(function(err, db) {
        if(!err) {
            console.log("DB is ready for dogfight at port " + port);
        }
    });
};

şeklinde bağlantı adresi ve port numarası alıyoruz. Sadece DB adı belirttiğimizde otomatik DB eklemnesi işlemi yapılmış oluyor. Her seferinde yeni DB yaratmak için gibi kod yazılsa da var olan DB varsa üzerine yazmaya devam ediyor. Yukarıda da bahsettiğim gibi, şema değişikleri önceki veriyi değiştirme zorunda değil. Aynı durum DB ekleme düzenleme durumu için de geçerlidir.
DB.prototype.getCollection = function(callback) {
    this.db.collection('posts', function(error, post_collection) {
        if(error)
            callback(error);
        else
            callback(null, post_collection);
    });
};
Şablon adını verip('posts') bir koleksiyona atayıp bu koleksiyon ile yaptığımız tüm işlemlerde aslında DB ile işlemi tamamlamış oluyoruz.


DB.prototype.save = function(posts, callback) {
    this.getCollection(function(error, post_collection) {
        if(error)
            callback(error);
        else {
            if(typeof (posts.length) == "undefined")
                posts = [posts];
            for(var i = 0; i < posts.length; i++) {
                post = posts[i];
                post.id = new ObjectID();
                if(post.created_at === undefined)
                    post.created_at = new Date();
            }
            post_collection.insert(posts, function() {
                callback(null, posts);
            });
        }
    });
};

Kayıt eklemek için koleksiyona insert diyerek eklemiş oluyoruz ve yeni datamızı saklamış oluyoruz.




Node v.0.8.6 -  Git
jade@0.27.2 node_modules\jade
├── commander@0.6.1
└── mkdirp@0.3.0
 
mongodb@1.1.4 node_modules\mongodb
└── bson@0.1.1
 
express@3.0.0rc3 node_modules\express
├── methods@0.0.1
├── fresh@0.1.0
├── cookie@0.0.4
├── commander@0.6.1
├── range-parser@0.0.4
├── crc@0.2.0
├── debug@0.7.0
├── mkdirp@0.3.3
├── send@0.0.3 (mime@1.2.6)
└── connect@2.4.3 (pause@0.0.1, bytes@0.1.0, qs@0.4.2, formidable@1.0.11)

Hiç yorum yok:

Yorum Gönder