基於C#的MongoDB數據庫開發應用(1)--MongoDB數據庫的基礎知識和使用

在花了很多時間研究學習了MongoDB數據庫的相關知識,以及利用C#對MongoDB數據庫的封裝、測試應用後,決定花一些時間來總結一下最近的研究心得,把這個數據庫的應用單獨做爲一個系列來介紹,但願從各個方面來總結並記錄一下這個新型、看似神祕的數據庫使用過程。本文是這個系列的開篇,主要介紹一些MongoDB數據庫的基礎知識、安裝過程、基礎使用等方面。git

MongoDB是一款由C++編寫的高性能、開源、無模式的經常使用非關係型數據庫產品,是非關係數據庫當中功能最豐富、最像關係數據庫的數據庫。它擴展了關係型數據庫的衆多功能,例如:輔助索引、範圍查詢、排序等。 程序員

MongoDB主要解決的是海量數據的訪問效率問題,它做爲分佈式數據崛起後,使用較多的一款非結構數據庫,必然有其值得稱道之處,它的主要功能特性以下:github

        1)面向集合的存儲,適合存儲對象及JSON形式的數據。
        2)動態查詢,MongoDB支持豐富的查詢表達式。查詢指令使用JSON形式的標記,可輕易查詢文檔中內嵌的對象及數組。
        3)完整的索引支持,包括文檔內嵌對象及數組。MongoDB的查詢優化器會分析查詢表達式,並生成一個高效的查詢計劃。
        4)查詢監視,MongoDB包含一個監視工具用於分析數據庫操做的性能。
        5)複製及自動故障轉移,MongoDB數據庫支持服務器之間的數據複製,支持主-從模式及服務器之間的相互複製。複製的主要目標是提供冗餘及自動故障轉移。
        6)高效的傳統存儲方式,支持二進制數據及大型對象(如圖片或視頻)。
        7)自動分片以支持雲級別的伸縮性,自動分片功能支持水平的數據庫集羣,可動態添加額外的機器。 正則表達式

一、MongoDB數據庫和傳統關係數據庫的對比

MongoDB數據庫有幾個簡單的概念須要瞭解一下。sql

 

    1)MongoDB中的 database 有着和咱們熟知的"數據庫"同樣的概念 (對 Oracle 來講就是 schema)。一個 MongoDB 實例中,能夠有零個或多個數據庫,每一個都做爲一個高等容器,用於存儲數據。mongodb

    2)數據庫中能夠有零個或多個 collections (集合)。集合和傳統意義上的 table 基本一致,能夠簡單的把二者當作是同樣的東西。數據庫

    3)集合是由零個或多個 documents (文檔)組成。一樣,一個文檔能夠當作是一 row數組

    4)文檔是由零個或多個 fields (字段)組成。,對應的就是關係數據庫的 columns緩存

    5)Indexes (索引)在 MongoDB 中扮演着和它們在 RDBMS 中同樣的角色,都是爲了提升查詢的效率。服務器

    6)Cursors (遊標)和上面的五個概念都不同,可是它很是重要,而且常常被忽視,其中最重要的你要理解的一點是,遊標是當你問 MongoDB 拿數據的時候,它會給你返回一個結果集的指針而不是真正的數據,這個指針咱們叫它遊標,咱們能夠拿遊標作咱們想作的任何事情,好比說計數或者跨行之類的,而無需把真正的數據拖下來,在真正的數據上操做。

 它們的對比關係圖以下所示。

數據在Mongodb裏面都是以Json格式方式進行存儲的,以下所示是其中的一個記錄內容。

{
    _id: ObjectID('4bd9e8e17cefd644108961bb'),
    name:'Vivek',
    class : '12th',
    subjects: [ 'physics', 'chemistry', 'math', 'english', 'computer'],
    address: {
                    house_no: '12B',
                    block: 'B',
                    sector: 12,
                    city : 'noida',
                    },
    grade: [
                    {
                    exam: 'unit test 1',
                    score: '60%'
                    },
                    {
                    exam: 'unit test 2',
                    score: '70%'
                    }
                    
                ]                
}

在過去的很長一段時間中,關係型數據庫一直是最主流的數據庫解決方案,他運用真實世界中事物與關係來解釋數據庫中抽象的數據架構。然而,在信息技術爆炸式發展的今天,大數據已經成爲了繼雲計算,物聯網後新的技術革命,關係型數據庫在處理大數據量時已經開始吃力,開發者只能經過不斷地優化數據庫來解決數據量的問題,但優化畢竟不是一個長期方案,因此人們提出了一種新的數據庫解決方案來迎接大數據時代的到來——NoSQL(非關係型數據庫),其中MongoDB數據庫就是其中的NoSQL的傑出表明。在大數據時代中,大數據量的處理已經成了考量一個數據庫最重要的緣由之一。而MongoDB的一個主要目標就是儘量的讓數據庫保持卓越的性能,這很大程度地決定了MongoDB的設計。

根據MongoDB官網的說明,MongoDB的適用場景以下:

1)網站實時數據:MongoDB很是適合實時的插入,更新與查詢,並具有網站實時數據存儲所需的複製及高度伸縮性。

2)數據緩存:因爲性能很高,MongoDB也適合做爲信息基礎設施的緩存層。在系統重啓以後,由MongoDB搭建的持久化緩存層能夠避免下層的數據源過載。

3)大尺寸、低價值數據存儲:使用傳統的關係型數據庫存儲一些數據時可能會比較昂貴,在此以前,不少時候程序員每每會選擇傳統的文件進行存儲。

4)高伸縮性場景:MongoDB很是適合由數十或數百臺服務器組成的數據庫。MongoDB的路線圖中已經包含對MapReduce引擎的內置支持。

5)對象或JSON數據存儲:MongoDB的BSON數據格式很是適合文檔化格式的存儲及查詢。


MongoDB不適合使用場景以下:
1)高度事務性系統:例如銀行或會計系統。傳統的關係型數據庫目前仍是更適用於須要大量原子性復瑣事務的應用程序。

2)傳統的商業智能應用:針對特定問題的BI數據庫會對產生高度優化的查詢方式。
3)須要複雜SQL查詢的問題。

MongoDB大多數狀況下,能夠代替關係型數據庫實現數據庫業務。它更簡單更直接、更快速而且一般對應用開發者的約束更少,不過缺少事務支持須要慎重考慮業務須要。

 

二、MongoDB數據庫的安裝及基礎使用

MongoDB數據的官網爲:https://www.mongodb.org/,當前版本爲3.2,能夠直接下載安裝版本在Linux或者Windows進行安裝。

通常在Windows,咱們默認安裝的路徑爲C:\Program Files\MongoDB,安裝後能夠手動建立一個放置數據庫和日誌文件的目錄,通常不要放在C盤就好,以下所示:

建立文件夾d:\mongodb\data\db、d:\mongodb\data\log,分別用來安裝db和日誌文件,咱們之後運行數據庫後,這個目錄就用來放置咱們建立的數據庫和日誌資源了。

通常咱們安裝後,爲了在命令行方便調用Mongodb的命令,咱們能夠設置一個全局的路徑變量,以下所示。

默認狀況下,mongodb的工做模式,是啓動一個DOS窗口,運行mongodb的數據庫服務,一旦這個DOS窗口關閉,也就中止了相關的服務,在Windows平臺,咱們能夠把它寄宿在Windows服務裏面,讓它隨着系統的啓動而啓動,也沒必要由於誤關閉窗口而中止了數據庫服務了。

經過下面命令行執行數據庫服務的處理。

mongod --dbpath "d:\mongodb\data\db" --logpath "d:\mongodb\data\log\MongoDB.log" --install --serviceName "MongoDB"

而後使用命令行啓動服務

NET START MongoDB

建立服務並順利啓動成功後,而後就能夠在系統的服務列表裏查看到了,咱們確認把它設置爲自動啓動的Windows服務便可。

啓動後,咱們能夠在系統【運行】裏面直接使用命令mongo打開窗口就能夠進行相關的操做了。

上面用了一些常見的命令操做。

  • show dbs    顯示數據庫列表
  • use dbname    進入dbname數據庫,大小寫敏感,沒有這個數據庫也沒關係
  • show collections    顯示數據庫中的集合,至關於表格
  • db.<collection_name>.find(); 集合查找方法,參考上面的方式,使用pretty()函數是排版更好看的意思。

 而其中find方法很強大,能夠組合不少條件查詢的方式,以下所示:

  • db.collection.find({ "key" : value })    查找key=value的數據
  • db.collection.find({ "key" : { $gt: value } })    key > value
  • db.collection.find({ "key" : { $lt: value } })    key < value
  • db.collection.find({ "key" : { $gte: value } })    key >= value
  • db.collection.find({ "key" : { $lte: value } })    key <= value
  • db.collection.find({ "key" : { $gt: value1 , $lt: value2 } })    value1 < key <value2
  • db.collection.find({ "key" : { $ne: value } })    key <> value
  • db.collection.find({ "key" : { $mod : [ 10 , 1 ] } })    取模運算,條件至關於key % 10 == 1 即key除以10餘數爲1的
  • db.collection.find({ "key" : { $nin: [ 1, 2, 3 ] } })    不屬於,條件至關於key的值不屬於[ 1, 2, 3 ]中任何一個
  • db.collection.find({ "key" : { $in: [ 1, 2, 3 ] } })    屬於,條件至關於key等於[ 1, 2, 3 ]中任何一個
  • db.collection.find({ "key" : { $size: 1 } })    $size 數量、尺寸,條件至關於key的值的數量是1(key必須是數組,一個值的狀況不能算是數量爲1的數組)
  • db.collection.find({ "key" : { $exists : true|false } })    $exists 字段存在,true返回存在字段key的數據,false返回不存在字度key的數據
  • db.collection.find({ "key": /^val.*val$/i })    正則,相似like;「i」忽略大小寫,「m」支持多行
  • db.collection.find({ $or : [{a : 1}, {b : 2} ] })    $or或 (注意:MongoDB 1.5.3後版本可用),符合條件a=1的或者符合條件b=2的數據都會查詢出來
  • db.collection.find({ "key": value , $or : [{ a : 1 } , { b : 2 }] })    符合條件key=value ,同時符合其餘兩個條件中任意一個的數據
  • db.collection.find({ "key.subkey" :value })    內嵌對象中的值匹配,注意:"key.subkey"必須加引號
  • db.collection.find({ "key": { $not : /^val.*val$/i } })    這是一個與其餘查詢條件組合使用的操做符,不會單獨使用。上述查詢條件獲得的結果集加上$not以後就能得到相反的集合。

固然還有插入更新的處理語句也是很特別的。

db.student.insert({name:'student1',subject:['arts','music']})

特別是更新操做須要說明一下,支持常規的$set方法(修改)、$unset方法(移除指定的鍵),還有原子級的$inc方法(數值增減),$rename方法(重命名字段名稱)等等,

db.users.update({"_id" : ObjectId("51826852c75fdd1d8b805801")},  {"$set" : {"hobby" :["swimming","basketball"]}} )
db.users.update({"_id" : ObjectId("51826852c75fdd1d8b805801")},{"$unset" : {"hobby" :1 }} )
db.posts.update({"_id" : ObjectId("5180f1a991c22a72028238e4")}, {"$inc":{"pageviews":1}})
db.students.update( { _id: 1 }, { $rename: { 'nickname': 'alias', 'cell': 'mobile' } } 

upsert是一種特殊的更新操做,不是一個操做符。(upsert = up[date]+[in]sert),也就是若是存在則更新,不然就寫入一條新的記錄操做。這個參數是個布爾類型,默認是false。

db.users.update({age :25}, {$inc :{"age" :3}}, true)

另外,Update能夠對Json的集合進行處理,若是對於subject對象是一個集合的話,插入或更新其中的字段使用下面的語句

db.student.update({name:'student5'},{$set:{subject:['music']}},{upsert:true});

若是是記錄已經存在,咱們可使用索引數值進行更新其中集合裏面的數據,以下所示。

db.student.update({name:'student3'},{$set:{'subject.0':'arts'}});

若是咱們先在集合裏面增長一個記錄,而非替換的話,那麼使用$push語句,以下面的語句所示。

db.student.update({name:'student3'},{$push:{'subject':'sports'}})

相反,若是要移除集合裏面的某個值,使用$pop操做符,那麼語句以下所示

db.student.update({name:'student3'},{$pop:{'subject':1}});

其中索引爲1標識最右邊的記錄,-1標識爲最左邊的記錄。

另外還可使用$pushAll 和$pullAll來增長/移除一個或多個集合記錄,以下代碼所示。

db.student.update({name:'student3'},{$pushAll:{'subject':['sports','craft']}})
db.student.update({name:'student3'},{$pullAll:{'subject':['sports','craft']}})

 

mongodb的數據庫的操做仍是比較容易理解的,具體能夠進一步參考官網裏面的介紹。

https://docs.mongodb.org/manual/

https://docs.mongodb.org/getting-started/csharp/client/

http://mongodb.github.io/mongo-csharp-driver/2.2/

http://wiki.jikexueyuan.com/project/the-little-mongodb-book/

 

三、MongoDB數據庫的C#驅動的使用

 數據庫的C#驅動使用介紹,能夠參考:https://docs.mongodb.org/getting-started/csharp/,或者http://mongodb.github.io/mongo-csharp-driver/2.2/,能夠下載相關的DLL而後在項目中引用,當前的驅動版本爲2.2,通常引入下面幾個DLL便可。

    • MongoDB.Bson.dll
    • MongoDB.Driver.dll
    • MongoDB.Driver.Core.dll

也可使用VS工具的NugGet包進行下載管理,以下所示。

而後在彈出的NugGet程序包管理界面裏面搜索mongo,而後添加MongoDB.Driver的數據庫驅動就可使用了。

MongoDB數據庫驅動在2.2版本(或者是從2.0開始)好像徹底改寫了API的接口,所以目前這個版本同時支持兩個版本的API處理,一個是基於MongoDatabase的對象接口,一個是IMongoDatabase的對象接口,前者中規中矩,和咱們使用Shell裏面的命令名稱差很少,後者IMongoDatabase的接口是基於異步的,基本上和前者差異很大,並且接口都提供了異步的處理操做。後面我會分別對這兩個部分進行詳細的介紹,本文基於篇幅的緣由,介紹一下二者的簡單差別就能夠了。

咱們以Mongodb的數據庫鏈接字符串mongodb://localhost/local來進行構建

1)舊接口MongoDatabase對象的構建

            var client = new MongoClient(connectionString);
            var database = client.GetServer().GetDatabase(new MongoUrl(connectionString).DatabaseName);

2)新接口IMongoDatabase對象的構建

            var client = new MongoClient(connectionString);
            var database = client.GetDatabase(new MongoUrl(connectionString).DatabaseName);

後者已經沒有了GetServer的接口了。

3)舊接口的查找對象處理

        /// <summary>
        /// 查詢數據庫,檢查是否存在指定ID的對象
        /// </summary>
        /// <param name="key">對象的ID值</param>
        /// <returns>存在則返回指定的對象,不然返回Null</returns>
        public virtual T FindByID(string id)
        {
            ArgumentValidation.CheckForEmptyString(id, "傳入的對象id爲空");

            MongoCollection<T> collection = GetCollection();
            return collection.FindOneById(new ObjectId(id)); 
        }

3)新接口查找對象的處理

        /// <summary>
        /// 查詢數據庫,檢查是否存在指定ID的對象
        /// </summary>
        /// <param name="key">對象的ID值</param>
        /// <returns>存在則返回指定的對象,不然返回Null</returns>
        public virtual T FindByID(string id)
        {
            ArgumentValidation.CheckForEmptyString(id, "傳入的對象id爲空");

            IMongoCollection<T> collection = GetCollection();
            return collection.Find(s=> s.Id == id).FirstOrDefault();
        }

新接口已經沒有了FindOneById等接口了,全部的操做基本上都經過Find方法進行處理。舊接口不少經過Query對象進行條件的查詢,新接口又換了一個對象進行過濾條件處理了,總的來講,兩個接口差別很是大。

例如舊版本接口的Query使用C#代碼以下所示:

        private void TestQuery()
        {
            Query.All("name", new List<BsonValue> { BsonValue.Create("a"), BsonValue.Create("b") });//經過多個元素來匹配數組
            Query.And(Query.EQ("name", "a"), Query.EQ("title", "t"));//同時知足多個條件
            Query.Or(Query.EQ("name", "a"), Query.EQ("title", "t"));//知足其中一個條件
            Query.EQ("name", "a");//等於
            Query.Exists("type");//判斷鍵值是否存在
            Query.GT("value", 2);//大於>
            Query.GTE("value", 3);//大於等於>=
            Query.In("name", new List<BsonValue> { BsonValue.Create("a"), BsonValue.Create("b") });//包括指定的全部值,能夠指定不一樣類型的條件和值
            Query.LT("value", 9);//小於<
            Query.LTE("value", 8);//小於等於<=
            Query.Mod("value", 3, 1);//將查詢值除以第一個給定值,若餘數等於第二個給定值則返回該結果
            Query.NE("name", "c");//不等於
            Query.Size("name", 2);//給定鍵的長度
            Query.Type("_id", BsonType.ObjectId);//給定鍵的類型
            Query.ElemMatch("children", Query.And( Query.EQ("name", "C3"),   Query.EQ("value", "C")));

            //Query.Nor(Array);//不包括數組中的值
            //Query.Not("name");//元素條件語句
            //Query.NotIn("name", "a", 2);//返回與數組中全部條件都不匹配的文檔
            //Query.Where(BsonJavaScript);//執行JavaScript

            //Query.Matches("Title", str);//模糊查詢 至關於sql中like  -- str可包含正則表達式
            var keyword = "abc";
            Query.Matches("Title", new BsonRegularExpression("/.*" + keyword + ".*/"));//模糊Like語法

            //經過正則表達式 1開頭 第二位數0~9且只能一位數,也包含20
            var queryName = Query.Matches("Name", new BsonRegularExpression("Donma1([0-9]{1,1})$|20"));
            //查找年齡 >=10 且<=20 
            var queryAge = Query.And(Query.GTE("Age", 10), Query.LTE("Age", 20));

            var entityQuery = Query<UserInfo>.EQ(e => e.Name, "wuhuacong");
            var entityQuery2 = Query<UserInfo>.EQ(e => e.Id, "4B414D000000011613CD");
        }

新版本的條件查詢,則丟棄了Query這個對象,提供了FilterDefinition<T> 對象的處理,估計是這個能夠處理的更好吧,同時新接口所有支持異步的處理操做了。

如插入記錄的異步操做代碼以下所示。

        /// <summary>
        /// 插入指定對象到數據庫中
        /// </summary>
        /// <param name="t">指定的對象</param>
        public virtual async Task InsertAsync(T t)
        {
            ArgumentValidation.CheckForNullReference(t, "傳入的對象t爲空");

            IMongoCollection<T> collection = GetCollection();
            await collection.InsertOneAsync(t);
        }

好了,基於篇幅的緣由,把後面介紹的C#開發留到下一篇進行介紹,但願本篇文章對你們瞭解mongodb數據庫,以及如何在C#上面使用該數據庫提供了一個簡要的指引,但願你們多多支持。

相關文章
相關標籤/搜索