MongoDB概要
[關於MongoDB]
官方網站: www.mongodb.com
MongoDB屬於比較典型的NoSql數據庫。和Relationship數據庫相比,其數據屬於文檔結構。
最新版本的MongoDB為2.2.2 不支持WindowsXP
[C#官方驅動程序]
GitHub:https://github.com/mongodb/mongo-csharp-driver
[管理工具]
這里選用本人自制的可視化管理工具作為教程的演示工具。
大聲呼吁:有興趣的同志,加入這個工具的開發
下載地址: http://www.wojilu.com/Forum1/Topic/4601
GitHub: https://github.com/magicdict/MagicMongoDBTool
[建立第一個空數據庫]
關於MongoDB的安裝,已經有很多文章介紹了。
這里推薦CNBLOGS網友 百靈 的Mongodb之(初識如故)
安裝這篇文章,應該可以正確安裝MongoDB,其實就是下載和解壓,完全綠色軟件。
這個系列的教程,我將MongoDB解壓到:C:\runmongo,可執行文件則都在C:\runmongo\bin下面。
新建一個MongoDB實例的方法很多,這里我新建了一個BAT文件,在BAT文件里面寫了3句命令:
第一句:將執行目錄切換到Mongo可執行目錄
第二句:新建一個目錄,MongoDB實例需要一個存放文件的目錄,這里我選擇新建一個C:\mongodb\magicdict 目錄
第三句,則是新建一個MongoDB實例,同時,將MongoDB實例的偵聽端口設置為 28030
關於MongoDB的啟動參數,推薦 咫尺天涯的文章:mongodb啟動參數
1 cd C:\runmongo\bin 2 mkdir C:\mongodb\magicdict 3 mongod --port 28030 --dbpath C:\mongodb\magicdict --rest
如果成功的話,將會有一個黑色的DOS控制台出現。當然,這個控制台只是日志輸出,無法操作。你也可以將日志存放到一個文件里面。
這個時候去查看 C:\mongodb\magicdict,系統自動添加了一個 mongod.lock 鎖文件。
接下來,啟動可視化工具,看看數據庫吧。
第一次啟動時候,選擇語言:
由於某些功能需要使用mongo的可執行文件,在可執行文件里面選擇可執行文件路徑
下面是連接管理界面,里面列出了所有現存的連接
單擊添加按鈕
由於是最簡單的數據庫,我們只需要填寫 連接名稱,主機,端口號即可。
連接名稱:這個可以使任意字符,是便於用戶記憶的。
主機:這里填寫服務器的IP地址,這里使用 localhost 表示本機
端口:28030
這里你可以先使用 [測試] 按鈕,檢驗一下設置是否正確。如果沒有問題,則可以[添加]連接。
選中剛才建立的連接,按下[確定]按鈕。則進入主界面。
界面左邊的是當前連接(MongoDB實例)中所包含的數據庫對象。當然,這個連接里面只是單純的數據庫。除了有一個系統自動生成的local數據庫以外,什么都沒有。
界面右邊的是當前連接的狀態信息。 關於這些狀態信息,你可以參看官方的幫助文檔: http://docs.mongodb.org/manual/reference/server-status/
一般來說,我們不會在local系統目錄里面添加數據,一般都會新建一個數據庫來保存用戶數據。
當然,你可以 選中Connection節點,然后用主菜單或者右鍵菜單來 [新建數據庫]。不過,這里將演示如何使用C#來創建數據庫,添加數據。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using MongoDB.Driver; 6 using MongoDB.Bson; 7 using MongoDB.Driver.GridFS; 8 using MongoDB.Bson.Serialization.Attributes; 9 10 namespace MagicMongoDBTool.Module 11 { 12 public static class InitTestData 13 { 14 internal class User 15 { 16 [BsonId] 17 public String ID; 18 [BsonElementAttribute("fn")] 19 public String Name; 20 public Byte Age; 21 public Byte Age2; 22 public Byte Age3; 23 public Address address; 24 } 25 internal class Address 26 { 27 public String street; 28 public String City; 29 public String state; 30 public int Zip; 31 32 } 33 internal class GeoObject 34 { 35 [BsonId] 36 public String ID; 37 public int[] Geo; 38 } 39 internal class TLLObject 40 { 41 [BsonId] 42 public String ID; 43 public DateTime CreateDateTime; 44 public int Game; 45 } 46 public static void FillDataForGeoObject(MongoServer mongosvr) 47 { 48 MongoDatabase mongodb = mongosvr.GetDatabase("mongodb"); 49 MongoCollection<User> mongoCol = mongodb.GetCollection<User>("GEO"); 50 mongoCol.RemoveAll(); 51 Random Ro = new Random(); 52 ///HugeData 53 for (int i = 0; i < 1000; i++) 54 { 55 mongoCol.Insert(new GeoObject() 56 { 57 ID = i.ToString(), 58 Geo = new int[2] { Ro.Next() % 180, Ro.Next() % 180 } 59 //[-180,180] 如果已經有索引,則操作這個范圍的記錄無法插入數據庫 60 }); 61 } 62 } 63 public static void FillDataForTTL(MongoServer mongosvr) 64 { 65 MongoDatabase mongodb = mongosvr.GetDatabase("mongodb"); 66 MongoCollection<User> mongoCol = mongodb.GetCollection<User>("TTL"); 67 mongoCol.RemoveAll(); 68 Random Ro = new Random(); 69 ///HugeData 70 for (int i = 0; i < 1000; i++) 71 { 72 mongoCol.Insert(new TLLObject() 73 { 74 ID = i.ToString(), 75 CreateDateTime = System.DateTime.Now.AddSeconds(i), 76 Game = Ro.Next() 77 }); 78 } 79 } 80 public static void FillDataForUser(MongoServer mongosvr) 81 { 82 MongoDatabase mongodb = mongosvr.GetDatabase("mongodb"); 83 84 MongoCollection<BsonDocument> mongoJsCol = mongodb.GetCollection<BsonDocument>("system.js"); 85 mongoJsCol.Insert<BsonDocument>( 86 new BsonDocument().Add("_id", "sum") 87 .Add("value", "function (x, y) { return x + y; }")); 88 MongoGridFS mongofs = mongodb.GetGridFS(new MongoGridFSSettings()); 89 MongoCollection<User> mongoCol = mongodb.GetCollection<User>("User"); 90 mongoCol.RemoveAll(); 91 Random Ro = new Random(); 92 ///HugeData 93 for (int i = 0; i < 1000; i++) 94 { 95 mongoCol.Insert(new User() 96 { 97 ID = i.ToString(), 98 Name = "Tom", 99 Age = (byte)Ro.Next(100), 100 Age2 = (byte)Ro.Next(100), 101 Age3 = (byte)Ro.Next(100), 102 address = new Address() 103 { 104 street = "123 Main St.", 105 City = "Centerville", 106 state = "PA", 107 Zip = Ro.Next(20) 108 } 109 }); 110 } 111 } 112 } 113 }
這里我新建了一個mongodb的數據庫,同時新增了3個演示用數據集(collection)。
具體的操作方法,推薦 碼農的文章: MongoDB的C#驅動程序教程(譯)
這里有非常詳細的C#操作數據庫的解釋。全部是官方文檔的翻譯,可能是機器翻譯的,但是對於英語不好的同志來說,有一定幫助。
當然,如果你的英語還可以,原汁原味的在這里:http://www.mongodb.org/display/DOCS/CSharp+Driver+Tutorial
MongoDB的對象存取,代碼看上去有點ORM的味道,不過,由於MongoDB已經是階層數據庫了,完全不需要將Object進行映射(Map),而是直接存取到數據庫中。
在簡單類的時候,由於數據結構只是二維表格,這種優勢不是很明顯。在復雜類的時候,出現層次結構的時候,則效果非常明顯。
下圖則通過[樹形視圖]來直觀展示了復雜階層的類。
關系型數據庫,需要將User數據和Address數據放在兩張表中,然后用主鍵連接成視圖。
階層型數據庫,則已經將User和Address信息放在一個文檔(Document,類似於記錄的概念)里面。
(當然,關系型的好處也非常明顯,可以減少數據冗余,靈活性也非常好。階層型數據庫在編碼上,可能更加貼近OOP)
[索引-TTL索引]
索引都是為了檢索的性能而生的,MongoDB的索引也不例外。
TTL(TimeToLive)索引(MongoDB2.2.2新增)和地理位置索引(“2d”)則是MongoDB的特色。
TTL索引,索引對象是一個日期型字段,然后需要設定一個有效時間。通過監視 日期型字段的值和當前系統時間,參考有效時間,判斷是否數據過期,對於過期的數據則自動刪除。
這個特性對於自動刪除日志這樣的操作來說,將非常有用。例如我們可以對於 日志創建時間 進行索引,同時設定過期時間為 3600秒,這樣系統將自動刪除一個小時之前的日志。
這里我們准備了TTL這樣的一個數據集:
數據集里面包含了一個CreateDateTime的日期型字段,里面存放着建立記錄的時間。
接着我們選中數據集,通過索引管理器建立索引。
我們將對於CreateDateTime建立所以,同時設定有效時間為180秒。
這樣的話,如果CreateDateTime和系統時間相差180秒,則記錄將會被自動刪除。
1.TTL索引必須建立在日期型字段(或者日期型字段數組)
2.不能建立在復雜索引上
3.你不能在 _id或者任何一個已經存在索引的字段上建立TTL索引
TTL索引的官方說明: http://docs.mongodb.org/manual/tutorial/expire-data/
注意上面這張圖的左邊,顯示了數據集的索引信息:
AutoDelete的索引過期時間為180秒。而默認的索引_id,則沒有設定過期時間。
同時,里面的數據已經全部被系統自動刪除掉了。
[索引-GEO索引]
如果,你的數據集里面有一個地理位置字段(所謂的地理位置字段,是一個數組,數組里面有兩個數字,數字的范圍是 [-180,180])。
例如,下面的Geo字段,就是一個地理位置字段。
我們可以對於地理位置字段,進行“2d”索引,或者說是Geo索引。
觀察一下索引類型:這里顯示的是 “2d”,表示這是一個Geo地理索引
建立過地理索引的數據集,可以進行GeoNear查詢。
官方文檔: http://docs.mongodb.org/manual/applications/geospatial-indexes/
GeoNear的意思就是:查詢一下,指定的坐標附近,有那些記錄。
你可以指定: 1.需要查詢多少個最鄰近的記錄。
2.你可以限制最大的距離。
3.由於地理坐標的單位是弧度【-180,180】,有時候你需要將距離放大一些,你可以指定距離乘積
4.Spherical(球形)
下面我們要查詢離坐標 【100,100】,距離在10以內的記錄,我們限制最多查詢100個記錄。
並且我們不需要系統對於距離進行放大或者縮小的處理。
查詢結果:我們掃描了23個記錄(由於有索引,所以不需要掃描全部記錄),掃描時間為0
符合條件的記錄有6個,平均距離為 6.34 最大距離為 9.21
每條記錄的詳細信息都可以在結果里面看到。