Klasik web uygulamaları, çok katmanlı mimari olarak tasarlanırlar. Her bir katmanın bir sorumluluğu vardır. Çok katmanlı yapıdaki her bir katman, kendinden önceki katmana hizmet verirken, kendinden sonraki katmandan hizmet alır. Şekil-1'de bu katmanlı yapıda yer alan 5 katman tanıtılmıştır:
- İ: İstemci katmanı. Çoğu zaman bir web tarayıcısıdır.
- S: Sunum katmanı. Uygulamanın kullanıcıya dönük yüzünü oluşturmaktan sorumludur. Sunum mantığını içerir.
- İM: İş Mantığı katmanı. İşin asıl yapıldığı yerdir.
- T: Tümleştirme katmanı. Kurumsal uygulamalar geliştirilirken çoğu zaman kurum içindeki ya da dışındaki diğer yazılımlarla etkileşim kurması istenir. Tümleştirme katmanı bu iletişimin sorunsuz gerçekleşmesinden sorumludur.
- K: Kaynak katmanı. Verilerin kalıcı olarak saklandığı katmandır. Veritabanı (Oracle, MySQL, DB2 gibi), Dizin sunucusu (Active Directory, OpenLDAP), CRM (Oracle Siebel, Microsoft Dynamics), ERP uygulaması gibi çok farklı türde olabilir.
Şekil-1: Klasik web mimarisi
İstemci ile sunucu arasındaki etkileşim istek-cevap örüntüsündedir. Uygulamanın arayüzünün değişmesi için mutlaka sunucuya bir isteğin gitmesi gerekir. Sunum mantığı da sunucuda yer alır. Bu durum mimarinin zayıf halkasını oluşturur. Sunumdaki her değişiklik mutlaka sunucuya uğramak zorundadır. Sunumdaki bu problemin, Ajax ile bir ölçüde gizlendiği söylenebilir. Ajax teknolojisi, istemcilerin isteklerini asenkron bir şekilde sunucuya iletmelerine olanak sağlamıştır. Ajax istek cevabı şimdi sadece arayüzdeki değişiklikleri içerebilmektedir. Bu sunucunun yükünü bir miktar azaltır.
Kaynak katmanında çoğu zaman ilişkisel veri tabanları kullanılır. İlişkisel veri tabanları, ilişki cebri üzerine kurulmuştur. 1970'li yıllardan beri geliştirilen, sınanmış olgun bir teknolojidir. Ama iş ölçeklenebilirliğe geldiğinde, doğası gereği, başarılı oldukları söylenemez. Her kurumsal uygulama, ilişkisel veri tabanına ihtiyaç duyar. Dolayısı ile veritabanları her zaman potansiyel bir dar boğaz noktasıdır.
Web tarayıcıları, HTML 5 ile birlikte gelen API'ler yardımı ile üzerinde uygulama koşturabileceğimiz platformlara dönüştüler:
- Canvas API,
- Data Storage API,
- Drag and Drop API,
- Messaging and Workers API,
- WebSocket API,
- Geolocation API
- Daha çok kullanıcı etkileşimi,
- Daha zengin kullanıcı deneyimi
- Mobil cihazlardan, hareket halindeyken erişim
- Değişen bant genişliklerinde çalışabilme
- Bağlantının kesildiği durumlarda da çalışabilmek
- Süper ölçeklenebilirlik
Şekil-2: İnce sunucu-donatımlı istemci modeli
Bu yeni mimaride sunucunun inceldiğini görüyoruz. İstemcilerin artık daha seyrek olarak ve daha çok veriye erişmek için sunucuya gittiklerini görüyoruz. İstemci tarafta programlama dili JS olduğu için veriye erişirken, en verimli kodlama biçimi Java Script Object Notation (JSON) olacaktır. HTTP protokolü üzerinden eriştiğimiz sunucuda, veri servisinin, kabul görmüş RESTful servis olarak tasarlandığını görüyoruz. RESTful servisler HTTP protokolünü kullanır. HTTP protokolü belleksiz yalın bir mantığa sahiptir. Dolayısı ile son derece ölçeklenebilir bir çözüm sunar. Tüm bu mimari değişimde, veri tabanı olarak sadece ilişkisel veri tabanı kullanamayız. Bu süreçte, ilişkisel veritabanları ile birlikte kullanılacak, yeni doğan ihtiyaçlara yanıt verebilecek yeni veritabanlarının türediği görüyoruz. Bu veri tabanlarına toplu olarak "Not Only SQL" anlamında NoSQL adını veriyoruz.
Şekil-3: Süper ölçeklenebilir model
Farklı türlerde NoSQL veri tabanları bulunuyor:
- (JSON) Doküman veri tabanları (MongoDB, CouchDB, OrientDB)
- Graf veri tabanları (Neo4j, OrientDB)
- Anahtar-Değer veri tabanları (Redis, OrientDB)
- Çok Kipli Veri tabanları (OrientDB)
Kurulum
MongoDB kurulum dosyasını bu bağlantıdan elinizdeki işletim sistemi için indirmeniz gerekiyor. Windows, Linux, Solaris ve MacOS platformları için MongoDB kurulum dosyası bulabilirsiniz. Açık kaynak kodlu bir proje olan MongnDB, C++'da yazılmıştır. Kaynak kodlara bu bağlantıdan erişebilirsiniz.
MongoDB kurulumu indirdiğiniz zip dosyasını uygun bir dizine açarak tamamlanıyor. Bu yazı için kurulumu Windows 8.1 x64 platformunda gerçekleştirdim. mongodb-win32-x86_64-2008plus-ssl-v3.4-latest.zip dosyasını c:\opt64 dizinine açtım ve dizini mongodb-3.4 olarak isimlendirdim. Tüm çalıştırılabilir dosyalar bin dizini içinde bulunuyor:
- mongo.exe: Komut satırı istemcisi
- mongod.exe: Sunucu yazılım
- mongodump.exe: Yedek almak için kullanılan yazılım. Yedekleme dosyaları bson formatındadır.
- bsondump.exe: bson formatındaki dosyaları komut satırından okumak için kullanılır.
- mongoexport.exe: MongoDB sunucuları arasında veri alış verişi için kullanılır.
- mongofiles.exe
- mongoimport.exe: MongoDB sunucuları arasında veri alış verişi için kullanılır. Bir örneğini yazının devamında bulabilirsiniz.
- mongooplog.exe
- mongoperf.exe
- mongorestore.exe: mongodump ile alınan bütün bir yedekten geri dönmek için kullanılır
- mongos.exe
- mongostat.exe: Unix'deki vmstat komutuna benzer bir işleve sahiptir. mongod sunucunun ekleme/silme/güncelleme başarımını izlemenize olanak sağlar:
mongostat connected to: 127.0.0.1 insert query update delete getmore command flushes mapped vsize res faults locked db idx miss % qr|qw ar|aw netIn netOut conn time *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 world:0.0% 0 0|0 0|0 62b 3k 1 01:32:24 *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 world:0.0% 0 0|0 0|0 62b 3k 1 01:32:25 *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 world:0.0% 0 0|0 0|0 62b 3k 1 01:32:26 *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 world:0.0% 0 0|0 0|0 62b 3k 1 01:32:27 *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 world:0.0% 0 0|0 0|0 62b 3k 1 01:32:28 *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 world:0.0% 0 0|0 0|0 62b 3k 1 01:32:29 *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 admin:0.0% 0 0|0 0|0 62b 3k 1 01:32:30 *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 world:0.0% 0 0|0 0|0 62b 3k 1 01:32:31 *0 *0 *0 *0 0 1|0 0 320m 2.91g 80m 0 world:0.0% 0 0|0 0|0 62b 3k 1 01:32:32
- mongotop.exe: Unix'deki top komutuna benzer bir işleve sahiptir. Bu kez mongod yönetimindeki torbaların kullanım istatistiklerini listeliyor:
mongotop connected to: 127.0.0.1 ns total read write world.system.namespaces 0ms 0ms 0ms world.system.js 0ms 0ms 0ms world.system.indexes 0ms 0ms 0ms world.movies1 0ms 0ms 0ms world.countries2 0ms 0ms 0ms world.countries1 0ms 0ms 0ms world.cities2 0ms 0ms 0ms local.system.replset 0ms 0ms 0ms
MongoDB istemci-sunucu mimarisine sahiptir. Sunucuyu başlatmak için mongod.exe programını kullanıyoruz. Sunucuya komut satırından bağlanmak için ise mongo.exe programını kullanıyoruz. MongoDB JSON dokümanlarını hızlı erişim için bellekte, kalıcı hale getirmek için ise BSON (Binary JSON) olarak diskte saklar. BSON, JSON formatındaki dokümanları bilgisayar ağı üzerinden etkin aktarımı için tasarlanmış bir formattır. Formatın detaylarına bu bağlantıdan erişebilirsiniz.
Sunucuyu komut satırından çalıştırmak için aşağıdaki komutları bir betik haline getirip çalıştırıyoruz:
SET MONGODB_HOME=c:\opt64\mongodb-3.4 SET PATH=%MONGODB_HOME%\bin;%PATH% start mongod --dbpath=%MONGODB_HOME%\data\db
Sunucunun ekran çıktısı aşağıda verilmiştir:
Windows servise eklemek için Administrator yetkisi ile aşağıdaki komutları çalıştırmak gerekir:
mkdir c:\opt64\mongodb-3.4\log echo logpath=c:\opt64\mongodb-3.4\log\mongolog > mongo.cfg set PATH=c:\opt64\mongodb-3.4\bin;%PATH% cd c:\opt64\mongodb-3.4 mongod --install --config c:\opt64\mongodb-3.4\mongo.cfg --dbpath c:\opt64\mongodb-3.4\data\db
Windows servise MongoDB adıyla eklenen sunucuyu başlatmak ve kapatmak için ne komutu yeterlidir:
net start MongoDB net stop MongoDB
Bundan sonraki örneklerde kullanmak üzere iki tane veri tabanını yükleyeceğiz. Bunun için mongoimport yazılımını kullanacağız. Örnek veri tabanlarını bu bağlantıdan indirip, örneğin c:\tmp dizinine açalım. İçinden çok sayıda json uzantılı dosya çıkacaktır:
- countries_v1.json
- countries_v2.json
- cities_v2.json
- directors_v2.json
- genres_v2.json
- movies_v1.json
- movies_v2.json
mongoimport --db imdb --collection movies1 --quiet --file c:\tmp\movies_v1.json --jsonArray mongoimport --db imdb --collection movies2 --quiet --file c:\tmp\movies_v2.json --jsonArray mongoimport --db imdb --collection directors2 --quiet --file c:\tmp\directors_v2.json --jsonArray mongoimport --db imdb --collection genres2 --quiet --file c:\tmp\genres_v2.json --jsonArray mongoimport --db world --collection countries1 --quiet --file c:\tmp\countries_v1.json --jsonArray mongoimport --db world --collection countries2 --quiet --file c:\tmp\countries_v2.json --jsonArray mongoimport --db world --collection cities2 --quiet --file c:\tmp\cities_v2.json --jsonArray
İlişkisel veri tabanlarında verileri tablolarda kayıtlar olarak saklıyoruz. MongoDB'de ilişkisel veri tabanlarındaki tablolara karşılık olarak torbalar (=Collection) yer alır. Tablolardaki kayıtlara karşılık olarak torbalarda, json dokümanlar yer alır (Şekil-4). İlişkisel veri tabanlarında, normalizasyon kurallarına uygun olarak, veri tutarlığını sağlamak ve veri tekrarı önlemek amacıyla, kayıtları tablolara dağıtıyoruz. Böylelikle, bu tablolar arasında, yabancı anahtarlar üzerinden, bire-bir, bire-çoklu, çokludan-bire ve çokludan-çokluya türünde ilişkiler yaratıyoruz. Bu yaklaşım, veri tutarlılığı açısından gerekli olsa da veriye okumak ya da değiştirmek amacıyla eriştiğimizde başarımın düşmesine neden olmaktadır. İlişkisel veri tabanları bu durumu aşmak için çeşitli çözümler geliştirseler de yüksek TPS (Transactions Per Second) değerleri önündeki en büyük engel olarak duruyor. MongoDB'de verileri aynı ilişkisel veri tabanlarında olduğu gibi farklı torbalara dağıtabilir ve bu torbalar arasında yabancı anahtarlar üzerinden ilişkiler kurabiliriz. Ancak MongoDB'de bu çalışma şeklinde yüksek başarım alınamaz, yüksek ölçeklenebilirliğe sahip uygulamalar geliştirilemez. Bunun yerine, torbalarda ilişkileriyle beraber tüm verileri saklamak daha uygun olur.
Şekil-4: MongoDB'de Veri tabanı, Torba ve Doküman İlişkisi
Örneğimizde, imdb veri tabanındaki movies1 torbasında, film bilgileri, json dokümanı olarak saklanmaktadır. movies1 torbasındaki bir filme ulaştığımızda, filmin adına, yılına, yönetmenlerinin bilgilerine ve tür bilgilerine ulaşıyoruz:
mongo MongoDB shell version: 3.4 connecting to: test > use imdb switched to db imdb > show collections directors2 genres2 histogram movies1 movies2 system.indexes > db.movies1.find({"_id": 1}) { "_id" : 1, "directors" : [ { "_id" : 1, "imdb" : "nm1989536", "name" : "Marc Webb" } ], "genres" : [ { "name" : "Comedy", "_id" : 1 }, { "name" : "Drama", "_id" : 2 }, { "name" : "Romance", "_id" : 3 } ], "imdb" : "tt10226 03", "title" : "500 Days Of Summer", "year" : 2007 } >
Buna karşılık olarak movies2 torbasında ise doğrudan yönetmen ve tür bilgisi bulunmuyor. Türlere ve yönetmenlere erişmek için ayrı torbalar var: directors2, genres2
mongo MongoDB shell version: 3.4 connecting to: test > use imdb switched to db imdb > db.movies2.find({"_id": 1}) { "_id" : 1, "directors" : [ { "id" : 1 } ], "genres" : [ { "id" : 1 }, { "id" : 2 }, { "id" : 3 } ], "imdb" : " tt1022603", "title" : "500 Days Of Summer", "year" : 2007 } >
Birinci tasarımda, veri tutarlılığını sağlamak geliştiricinin üstlendiği bir göreve dönüşmüştür. Buna karşılık birinci yöntemde veriye erişim başarımı en üst noktadadır. İkinci yöntemde ise veri tutarlılığı sağlanırken ve veri tekrarı önlenirken başarım düşecektir. Üstelik MongoDB'de tek bir torba üzerindeki tek bir ekleme, silme, güncelleme işlemleri atomik olarak gerçeklenir, ancak aynı ya da farklı torbalar üzerindeki bir dizi işlem, atomik olarak gerçeklenmesi garanti edilmez. MongoDB "transactional" bir veri tabanı değildir. Bu nedenle verilerin hayati derecede kritik olduğu, veri kaybına ya da tutarsızlığına tahammülün olmadığı uygulamalarda kullanılmamalıdır. Ancak ACID uyumluluğuna sahip "transactional" bir MongoDB sunucusu bulunuyor: TokuMX. Şimdilik sadece Linux dağıtımları mevcut. Ücretsiz açık kaynak kodlu topluluk sürümüne bu bağlantıdan erişebilirsiniz. TokuMX fraktal ağaç yaklaşımını kullanmaktadır.
Yükleme işleminin başarılı olduğunu test etmek için sunucuya mongo istemcisi ile bağlanalım ve veri tabanlarını ve bu veri tabanlarındaki torbaların listesini alalım:
mongo MongoDB shell version: 3.4 connecting to: test > show dbs admin (empty) imdb 0.078GB local 0.078GB world 0.078GB > use imdb switched to db imdb > show collections directors2 genres2 movies1 movies2 system.indexes > use world switched to db world > show collections cities2 countries1 countries2 system.indexes >
Torbalar Üzerinde Çalışmak
Çalışmaya önce bir torbaya kayıt ekleyerek başlayalım:
mongo MongoDB shell version: 3.4 connecting to: test > use imdb switched to db imdb > var tt2179136= {}; > tt2179136.title="American sniper"; American sniper > tt2179136.year=Number(2014); 2014 > tt2179136.imdb= "tt2179136"; tt2179136 > var nm0000142 = {}; > nm0000142.name= "Clint Eastwood"; Clint Eastwood > nm0000142.imdb= "nm0000142"; nm0000142 > tt2179136.directors= [ nm0000142 ]; [ { "name" : "Clint Eastwood", "imdb" : "nm0000142" } ] > var action= { "name": "Action"} > var biography= { "name": "Biography"} > var drama= { "name": "Drama"} > tt2179136.genres= [ action, biography, drama ]; [ { "name" : "Action" }, { "name" : "Biography" }, { "name" : "Drama" } ] > db.movies1.insert(tt2179136); WriteResult({ "nInserted" : 1 }) >
Eklediğimiz bu kayda ulaşmak için ise aşağıdaki çağrıyı oluşturuyoruz:
> db.movies1.findOne({ "imdb": "tt2179136"}) { "_id" : ObjectId("54d764fc492627f560e3fe41"), "title" : "American sniper", "year" : 2014, "imdb" : "tt2179136", "directors" : [ { "name" : "Clint Eastwood", "imdb" : "nm0000142" } ], "genres" : [ { "name" : "Action" }, { "name" : "Biography" }, { "name" : "Drama" } ] }
Dikkat edilirse, suncunun torbaya attığım json dokümana fazladan bir alan eklediği görülür: _id. Bu alan torbadaki her bir doküman için ister biz eklemiş olalım isterse de sunucu tarafından otomatik olarak verilmiş olsun, istisnasız vardır. _id alanı aslında ObjectId tipinde bir başka json nesnesidir. ObjectId 12 sekizlikten oluşan bir dizi alandan oluşur (Şekil-5). 4-Sekizlik boyutundaki ilk alan dokümanın eklenme tarihini saklar. Bu bilgiye getTimestamp() çağrısı ile ulaşabiliriz:
> var sniper= db.movies1.findOne({"title": /sniper/}); > sniper._id ObjectId("54d78d5bb93815e7249f4e6b") > sniper._id.getTimestamp() ISODate("2015-02-08T16:22:51Z") >
2-sekizlik boyundaki alan mongod prosesinin proses kimliğinden (PID), 3-sekizlik boyundaki alan makinanın IP değerinden ve 3-sekizlik alan ise sayaç değerinden oluşur. Bu şekilde _id değerinin tüm evrende tekil bir değer olması sağlanır. Bu kimlik değerini karakter katarı olarak okumak mümkündür:
> sniper._id.str 54d78d5bb93815e7249f4e6b > sniper._id.toString() ObjectId("54d78d5bb93815e7249f4e6b")
Şekil-5: ObjectID alanları
Sadece filmin adına ve yılına ulaşmak için ise ikinci bir parametre daha vermemiz gerekir:
> db.movies1.findOne({ "imdb": "tt2179136"},{"title": 1, "year":2, "_id": 0}) { "title" : "American sniper", "year" : 2014 }
Tüm filmlerin listesine ulaşmak için ise find() çağrısını kullanıyoruz:
> var cur= db.movies1.find({}) > cur.next() { "_id" : 1, "directors" : [ { "_id" : 1, "imdb" : "nm1989536", "name" : "Marc Webb" } ], "genres" : [ { "name" : "Comedy", "_id" : 1 }, { "name" : "Drama", "_id" : 2 }, { "name" : "Romance", "_id" : 3 } ], "imdb" : "tt1022603", "title" : "500 Days Of Summer", "year" : 2007 } >
find() her zaman bir imleç (=cursor) döner. Bu kayıtlara ulaşmak için bir JS nesnesidir. next() çağrısını kullanarak bir sonraki dokümana ulaşabiliriz. İmleci kullanarak skip() ve limit() çağrıları yardımı ile sayfalama yapmak mümkündür:
> var cur= db.movies1.find({},{"title": 1, "_id":0}) > cur.skip(10).limit(10) { "title" : "Armored" } { "title" : "Bornova Bornova" } { "title" : "Coco avant Chanel" } { "title" : "Nefes: Vatan sa?olsun" } { "title" : "Up" } { "title" : "Whiteout" } { "title" : "The Time Travelers Wife" } { "title" : "Whatever Works" } { "title" : "Anonyma - Eine Frau in Berlin" } { "title" : "Weather Girl" } >
Az önce eklediğimiz filmi silelim:
> db.movies1.remove( {"imdb": "tt2179136"}) WriteResult({ "nRemoved" : 1 }) > db.movies1.find( {"imdb": "tt2179136"})
world veri tabanındaki countries1 torbasındaki tüm Asya kıtasında yer alan ülkelerin nüfuslarını bir arttıralım:
> use world switched to db world > db.countries1.find({"continent": "Asia"}).forEach( ... function(country){ ... db.countries1.findAndModify({ ... query:{"_id" : country._id }, ... update:{ ... $inc:{population: 1} ... } ... }); ... }); >
Torbalar Üzerinde Sorgu Çalıştırmak
MongoDB'yi yine JS kullanarak sorgulayacağız. Bunun için hem imdb hem de world veri tabanları üzerinde bir dizi sorgu problemini sırayla çalışacağız.
1. Tüm kıtaların listesi:
> use world switched to db world > db.countries1.distinct('continent') [ "North America", "Asia", "Africa", "Europe", "Oceania", "South America" ]
2. Toplam kıta sayısı:
> use world
switched to db world
> db.countries1.distinct('continent').length
6
3. Her bir kıtadaki ülke sayısı:
> use world switched to db world > db.countries1.group( ... { ... "key": { "continent": 1}, initial: {count :0}, ... "reduce": function(c,h){ h.count = h.count +1;} ... } ... ); [ { "continent" : "North America", "count" : 37 }, { "continent" : "Asia", "count" : 51 }, { "continent" : "Africa", "count" : 58 }, { "continent" : "Europe", "count" : 46 }, { "continent" : "South America", "count" : 14 }, { "continent" : "Oceania", "count" : 28 }, { "continent" : "Antarctica", "count" : 5 } ]
4. Her bir kıtadaki ülkelerin listesi:
> use world switched to db world > db.countries1.group( ... { ... "key": { "continent": 1}, ... "initial": { ... "countries" : [] ... }, ... "reduce": function(country,doc){ doc.countries.push(country.name);} ... } ... ); [ { "continent" : "North America", "countries" : [ "Aruba", "Anguilla", "Netherlands Antilles", "Antigua and Barbuda", "Bahamas", "Belize", "Bermuda", "Barbados", "Canada", "Costa Rica", "Cuba", "Cayman Islands", "Dominica", "Dominican Republic", "Guadeloupe", "Grenada", "Greenland", "Guatemala", "Honduras", "Haiti", "Jamaica", "Saint Kitts and Nevis", "Saint Lucia", "Mexico", "Montserrat", "Martinique", "Nicaragua", "Panama", "Puerto Rico", "El Salvador", "Saint Pierre and Miquelon", "Turks and Caicos Islands", "Trinidad and Tobago", "United States", "Saint Vincent and the Grenadines", "Virgin Islands, British", "Virgin Islands, U.S." ] }, { "continent" : "Asia", "countries" : [ "Afghanistan", "United Arab Emirates", "Armenia", "Azerbaijan", "Bangladesh", "Bahrain", "Brunei", "Bhutan", "China", "Cyprus", "Georgia", "Hong Kong", "Indonesia", "India", "Iran", "Iraq", "Israel", "Jordan", "Japan", "Kazakstan", "Kyrgyzstan", "Cambodia", "South Korea", "Kuwait", "Laos", "Lebanon", "Sri Lanka", "Macao", "Maldives", "Myanmar", "Mongolia", "Malaysia", "Nepal", "Oman", "Pakistan", "Philippines", "North Korea", "Palestine", "Qatar", "Saudi Arabia", "Singapore", "Syria", "Thailand", "Tajikistan", "Turkmenistan", "East Timor", "Turkey", "Taiwan", "Uzbekistan", "Vietnam", "Yemen" ] }, { "continent" : "Africa", "countries" : [ "Angola", "Burundi", "Benin", "Burkina Faso", "Botswana", "Central African Republic", "Côte d’Ivoire", "Cameroon", "Congo, The Democratic Republic of the", "Congo", "Comoros", "Cape Verde", "Djibouti", "Algeria", "Egypt", "Eritrea", "Western Sahara", "Ethiopia", "Gabon", "Ghana", "Guinea", "Gambia", "Guinea-Bissau", "Equatorial Guinea", "British Indian Ocean Territory", "Kenya", "Liberia", "Libyan Arab Jamahiriya", "Lesotho", "Morocco", "Madagascar", "Mali", "Mozambique", "Mauritania", "Mauritius", "Malawi", "Mayotte", "Namibia", "Niger", "Nigeria", "Réunion", "Rwanda", "Sudan", "Senegal", "Saint Helena", "Sierra Leone", "Somalia", "Sao Tome and Principe", "Swaziland", "Seychelles", "Chad", "Togo", "Tunisia", "Tanzania", "Uganda", "South Africa", "Zambia", "Zimbabwe" ] }, { "continent" : "Europe", "countries" : [ "Albania", "Andorra", "Austria", "Belgium", "Bulgaria", "Bosnia and Herzegovina", "Belarus", "Switzerland", "Czech Republic", "Germany", "Denmark", "Spain", "Estonia", "Finland", "France", "Faroe Islands", "United Kingdom", "Gibraltar", "Greece", "Croatia", "Hungary", "Ireland", "Iceland", "Italy", "Liechtenstein", "Lithuania", "Luxembourg", "Latvia", "Monaco", "Moldova", "Macedonia", "Malta", "Netherlands", "Norway", "Poland", "Portugal", "Romania", "Russian Federation", "Svalbard and Jan Mayen", "San Marino", "Slovakia", "Slovenia", "Sweden", "Ukraine", "Holy See (Vatican City State)", "Yugoslavia" ] }, { "continent" : "South America", "countries" : [ "Argentina", "Bolivia", "Brazil", "Chile", "Colombia", "Ecuador", "Falkland Islands", "French Guiana", "Guyana", "Peru", "Paraguay", "Suriname", "Uruguay", "Venezuela" ] }, { "continent" : "Oceania", "countries" : [ "American Samoa", "Australia", "Cocos (Keeling) Islands", "Cook Islands", "Christmas Island", "Fiji Islands", "Micronesia, Federated States of", "Guam", "Kiribati", "Marshall Islands", "Northern Mariana Islands", "New Caledonia", "Norfolk Island", "Niue", "Nauru", "New Zealand", "Pitcairn", "Palau", "Papua New Guinea", "French Polynesia", "Solomon Islands", "Tokelau", "Tonga", "Tuvalu", "United States Minor Outlying Islands", "Vanuatu", "Wallis and Futuna", "Samoa" ] }, { "continent" : "Antarctica", "countries" : [ "Antarctica", "French Southern territories", "Bouvet Island", "Heard Island and McDonald Islands", "South Georgia and the South Sandwich Islands" ] } ] >
5. 70'li yılların filmlerine, yıllara göre sıralı olarak erişmek:
> use imdb switched to db imdb > db.movies1.find( ... { ... 'year' : {$gte : 1970, $lt: 1980 } ... }, ... { ... "title": 1, "year":2 , "_id": 0 ... } ... ).sort({"year": 1}) { "title" : "Le magnifique", "year" : 1973 } { "title" : "Dog Day Afternoon", "year" : 1975 } { "title" : "Network", "year" : 1976 } { "title" : "The Little Girl Who Lives Down the Lane", "year" : 1976 } { "title" : "Der amerikanische Freund", "year" : 1977 } { "title" : "The Last Wave", "year" : 1977 }
6. Birden fazla yönetmeni olan filmlerin listesi:
> use imdb switched to db imdb > db.movies1.find( { $where: "this.directors.length > 1" } , {"title": 1, "_id":0 }) { "title" : "Gamer" } { "title" : "A Serious Man" } { "title" : "Rembetiko" } { "title" : "New York, I Love You" } { "title" : "Daybreakers" } { "title" : "The Imaginarium of Doctor Parnassus" } { "title" : "Cloudy with a Chance of Meatballs" } { "title" : "The Princess and the Frog" } { "title" : "Karamazovi" } { "title" : "The Missing Person" } { "title" : "Sonbahar" } { "title" : "I Love You Phillip Morris" } { "title" : "The Book of Eli" } >
7. Nufus yoğunluğu düşük olan ülkelerin listesi:
> use world switched to db world > db.countries1.find( ... { ... $and : [ ... { "population": { $lt: 1000000 } } , ... { "surfaceArea": { $gt: 100000 } } ... ] ... } , ... { ... "name": true, "population": true, "surfaceArea": true, "_id":false ... } ... ) { "name" : "Western Sahara", "population" : 293000, "surfaceArea" : 266012 } { "name" : "Greenland", "population" : 56000, "surfaceArea" : 2166102 } { "name" : "Guyana", "population" : 861000, "surfaceArea" : 214981 } { "name" : "Iceland", "population" : 279000, "surfaceArea" : 103012 } { "name" : "Suriname", "population" : 417000, "surfaceArea" : 163277 } >
8. 5 karakterli olan ülke adları:
> use world switched to db world > db.countries1.find( ... { name : /^....$/}, ... { name: 1 , _id: 0} ... ) { "name" : "Cuba" } { "name" : "Guam" } { "name" : "Iran" } { "name" : "Iraq" } { "name" : "Laos" } { "name" : "Mali" } { "name" : "Niue" } { "name" : "Oman" } { "name" : "Peru" } { "name" : "Chad" } { "name" : "Togo" }
9. 70'li yıllara ait Drama türündeki filmlere, film adına göre sıralı olarak erişmek:
> use imdb switched to db imdb > db.movies1.find( ... { ... $and : [ ... { 'year' : {$gte : 1970, $lt: 1980 } }, ... { 'genres.name': { $in: [ 'Drama' ] } } ... ] ... }, ... { ... "title": 1, "year":2 , "_id": 0 ... } ... ).sort({"title": 1}) { "title" : "Der amerikanische Freund", "year" : 1977 } { "title" : "Dog Day Afternoon", "year" : 1975 } { "title" : "Network", "year" : 1976 } { "title" : "The Last Wave", "year" : 1977 } { "title" : "The Little Girl Who Lives Down the Lane", "year" : 1976 }
10. Her bir film türünden kaç tane film olduğu bilgisine ulaşmak:
> db.movies1.aggregate( ... { $project: { "genres": 1} }, ... { $unwind: "$genres" }, ... { $group: { _id: "$genres.name" , total: { $sum: 1 } } } ... ); { "_id" : "Documentary", "total" : 1 } { "_id" : "Western", "total" : 7 } { "_id" : "Fantasy", "total" : 14 } { "_id" : "Sport", "total" : 7 } { "_id" : "Crime", "total" : 41 } { "_id" : "Family", "total" : 12 } { "_id" : "History", "total" : 12 } { "_id" : "Biography", "total" : 33 } { "_id" : "Adventure", "total" : 26 } { "_id" : "Action", "total" : 36 } { "_id" : "Animation", "total" : 9 } { "_id" : "Film-Noir", "total" : 2 } { "_id" : "Mystery", "total" : 33 } { "_id" : "Musical", "total" : 2 } { "_id" : "War", "total" : 18 } { "_id" : "Horror", "total" : 19 } { "_id" : "Romance", "total" : 56 } { "_id" : "Music", "total" : 7 } { "_id" : "Thriller", "total" : 70 } { "_id" : "Drama", "total" : 193 } { "_id" : "Sci-Fi", "total" : 15 } { "_id" : "Comedy", "total" : 65 }
Torbaları İndekslemek
Sistem tüm torbaları _id alanları üzerinden indeksler. İndekslemek erişim başarımı için önemlidir. Eğer sorgularda sıkça kullanılan alanlar var ise bu alanları da indekslemek uygun olur. Şimdi indekslenmemiş bir alan üzerinde bir sorgu çalıştırmanın maliyetini görelim:
> db.movies1.find({"year": 2010}).explain(); { "cursor" : "BasicCursor", "isMultiKey" : false, "n" : 18, "nscannedObjects" : 251, "nscanned" : 251, "nscannedObjectsAllPlans" : 251, "nscannedAllPlans" : 251, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 1, "nChunkSkips" : 0, "millis" : 4, "server" : "omegacw:27017", "filterSet" : false }
Sunucunun, bu sorguda tüm torbayı taraması gerekti. Şimdi year alanı üzerine bir indeks yaratalım:
> db.movies1.ensureIndex({ year: 1}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }
Yarattığımız indeksin etkisini, explain() çağrısı ile görmeye çalışalım:
> db.movies1.find({"year": 2010}).explain(); { "cursor" : "BtreeCursor year_1", "isMultiKey" : false, "n" : 18, "nscannedObjects" : 18, "nscanned" : 18, "nscannedObjectsAllPlans" : 18, "nscannedAllPlans" : 18, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 0, "nChunkSkips" : 0, "millis" : 0, "indexBounds" : { "year" : [ [ 2010, 2010 ] ] }, "server" : "omegacw:27017", "filterSet" : false }
İndekslemediğimizde toplam 251 dokümanı da taraması gerekmişti. İndeksledikten sonra ise olması gerektiği gibi sadece 18 tane dokümana erişti. Sorgu sonucunun 18 filmden oluştuğuna dikkat edin:
> db.movies1.find({"year": 2010}).length() 18
MongoDB ile ilgili daha detaylı bilgi edinmek için "Front-end Development and MongoDB" ve "Building Scalable Web Applications using Node.js, MondoDB, and Knockout.js" eğitimlerinin içeriklerini inceleyebilirsiniz.
No comments:
Post a Comment