快速掌握mongoDB(四)—— C#驅動MongoDB用法演示

撈月亮的猴子發表於2019-07-20

  前邊我們已經使用mongo shell進行增刪查改和聚合操作,這一篇簡單介紹如何使用C#驅動MongoDB。C#驅動MongoDB的本質是將C#的操作程式碼轉換為mongo shell,驅動的API也比較簡單明瞭,方法名和js shell的方法名基本都保持一致,熟悉mongo shell後學習MongoDB的C#驅動是十分輕鬆的,直接看幾個栗子吧。

0.準備測試資料

  使用js shell新增一些測試資料,如下:

use myDb
db.userinfos.insertMany([
   {_id:1, name: "張三", age: 23,level:10, ename: { firstname: "san", lastname: "zhang"}, roles: ["vip","gen" ]},
   {_id:2, name: "李四", age: 24,level:20, ename: { firstname: "si", lastname: "li"}, roles:[ "vip" ]},
   {_id:3, name: "王五", age: 25,level:30, ename: { firstname: "wu", lastname: "wang"}, roles: ["gen","vip" ]},
   {_id:4, name: "趙六", age: 26,level:40, ename: { firstname: "liu", lastname: "zhao"}, roles: ["gen"] },
   {_id:5, name: "田七", age: 27, ename: { firstname: "qi", lastname: "tian"}, address:'北京' },
   {_id:6, name: "周八", age: 28,roles:["gen"], address:'上海' }
])

1 新增(InsertOne,InsertMany)

  首先建立一個Console應用程式,使用命令  Install-Package MongoDB.Driver  新增C#的驅動包,然後就可以使用C#操作MongoDB資料庫了,看一個新增的栗子:

 class Program
    {
        static void Main(string[] args)
        {
            //連線資料庫
            var client = new MongoClient("mongodb://192.168.70.131:27017");
            //獲取database
            var mydb = client.GetDatabase("myDb");
            //獲取collection
            var collection = mydb.GetCollection<BsonDocument>("userinfos");
            //待新增的document
            var doc = new BsonDocument{
                { "_id",7 },
                { "name", "吳九" },
                { "age", 29 },
                { "ename", new BsonDocument
                    {
                        { "firstname", "jiu" },
                        { "lastname", "wu" }
                    }
                }
            };
            //InsertOne()新增單條docment
            collection.InsertOne(doc);
        }
    }

  執行完成後,檢視在RoboMongo中查詢,看到已經新增成功了:

  

我們也可以是用 collection.InsertMany(IEnumerable<BsonDocument> docs) 來批量新增docment,這裡就不再演示了。

2  查詢(Find,Filter,Sort,Projection)

1.簡單查詢(Find、Filter)

  栗子:查詢name=“吳九"的記錄

//Fileter用於過濾,如查詢name = 吳九的第一條記錄
var filter = Builders<BsonDocument>.Filter;
//Find(filter)進行查詢
var doc = collection.Find(filter.Eq("name","吳九")).FirstOrDefault();
Console.WriteLine(doc);

  查詢結果如下:

  如果我們想查詢所有的記錄,可以設定過濾器為空,程式碼為: var docs = collection.Find(filter.Empty).ToList(); 

2.AND查詢

 栗子:查詢年齡大於25且小於28的記錄

//查詢25<age<28的記錄
  var filter = Builders<BsonDocument>.Filter;
  var docs = collection.Find(filter.Gt("age", 25) & filter.Lt("age", 28)).ToList();
  docs.ForEach(d => Console.WriteLine(d));

   查詢結果如下:

 

3 OR查詢

  栗子:查詢年齡小於25或年齡大於28的記錄

//查詢age<25或age>28的記錄
  var filter = Builders<BsonDocument>.Filter;
  var docs = collection.Find(filter.Lt("age", 25) | filter.Gt("age", 28)).ToList();
  docs.ForEach(d => Console.WriteLine(d));

  查詢結果如下:

4 欄位存在(Exists)

  栗子:查詢包含address欄位的所有記錄

//查詢存在address欄位的記錄
  var filter = Builders<BsonDocument>.Filter;
  var docs = collection.Find(filter.Exists("address")).ToList();
  docs.ForEach(d => Console.WriteLine(d));

  查詢結果如下:

4 排序(Sort)

  栗子:查詢年齡小於26歲的記錄,並按年齡倒序排列

//查詢age<26的記錄,按年齡倒序排列
    var filter = Builders<BsonDocument>.Filter;
    var sort = Builders<BsonDocument>.Sort;
    var docs = collection.Find(filter.Lt("age",26))//過濾
                         .Sort(sort.Descending("age")).ToList();//按age倒序
    docs.ForEach(d => Console.WriteLine(d));

  查詢結果如下:

5 查詢指定欄位(Projection)

  MongoDB查詢會預設返回_id欄位,如果要不返回_id欄位可以使用Exclude("_id")將其排除。栗子:查詢年齡小於26歲記錄的name和age

//查詢age<26的記錄
    var project = Builders<BsonDocument>.Projection;
    var filter = Builders<BsonDocument>.Filter;
    var docs = collection.Find(filter.Lt("age", 26))//過濾
                         .Project(project.Include("name")//包含name
                                         .Include("age")//包含age
                                         .Exclude("_id")//不包含_id
                               ).ToList();
docs.ForEach(d => Console.WriteLine(d))        

  查詢結果:

 3 修改(UpdateOne,UpdateMany)

1 修改單條記錄(UpdateOne)

  修改符合過濾條件的第一條記錄,栗子:將張三的年齡改成18歲

            var filter = Builders<BsonDocument>.Filter;
            var update = Builders<BsonDocument>.Update;
            var project = Builders<BsonDocument>.Projection;
            //將張三的年齡改成18
            collection.UpdateOne(filter.Eq("name", "張三"), update.Set("age", 18));
            //查詢張三的記錄
            var doc = collection.Find(filter.Eq("name", "張三"))
                                .Project(project.Include("age").Include("name"))
                                .FirstOrDefault();
            Console.WriteLine(doc);

  執行結果:

2 修改多條記錄(UpdateMany)

  UpdateMany會修改所有符合過濾條件的記錄,栗子:將所有年齡小於25的記錄標記為young(如果沒有mark欄位會自動新增)

            var filter = Builders<BsonDocument>.Filter;
            var update = Builders<BsonDocument>.Update;
            var project = Builders<BsonDocument>.Projection;
            //將所有年齡小於25的記錄標記為young(如果沒有mark欄位會自動新增)
            UpdateResult reulst=collection.UpdateMany(filter.Lt("age",25), update.Set("mark", "young"));
            if (reulst.IsModifiedCountAvailable)
            {
                Console.WriteLine($"符合條件的有{reulst.MatchedCount}條記錄");
                Console.WriteLine($"一共修改了{reulst.ModifiedCount}條記錄");
               //查詢修改後的記錄
                var docs = collection.Find(filter.Empty)
                                .Project(project.Include("age").Include("name").Include("mark"))
                                .ToList();
                docs.ForEach(d => Console.WriteLine(d));
            }
            else
            {
                Console.WriteLine("無修改操作!");
            }

  查詢結果如下,可以看到age<25的記錄的mark欄位值為young:

4 刪除(DeleteOne和DeleteMany)

  刪除操作比較簡單,DeleteOne用於刪除符合過濾條件的第一條記錄,DeleteMany用於刪除所有符合過濾條件的記錄。

1 刪除單條記錄(DeleteOne)

  栗子:刪除名字為張三的記錄

            var filter = Builders<BsonDocument>.Filter;
            var project = Builders<BsonDocument>.Projection;
            //刪除名字為張三的記錄
            collection.DeleteOne(filter.Eq("name", "張三"));
            var docs = collection.Find(filter.Empty)
                            .Project(project.Include("age").Include("name").Include("mark"))
                            .ToList();
            docs.ForEach(d => Console.WriteLine(d));

  執行結果如下,我們看到張三的記錄已經被刪除了:

2  刪除多條記錄(DeleteMany)

  栗子:刪除所有年齡大於25歲的記錄

            var filter = Builders<BsonDocument>.Filter;
            var project = Builders<BsonDocument>.Projection;
            //刪除age>25的記錄
            DeleteResult result= collection.DeleteMany(filter.Gt("age", 25));
            Console.WriteLine($"一共刪除了{result.DeletedCount}條記錄");
            var docs = collection.Find(filter.Empty)
                            .Project(project.Include("age").Include("name").Include("mark"))
                            .ToList();
            docs.ForEach(d => Console.WriteLine(d));

  執行結果如下,所有年齡大於25歲的記錄都被刪除了:

 

5 型別對映

1 簡單栗子

 有時候我們要讓查詢的結果對映到我們的實體類中去,實現這個需求也十分簡單,mongoDB支援自動對映,直接使用泛型即可,看一個栗子:

    class Program
    {
        static void Main(string[] args)
        {
            //連線資料庫
            var client = new MongoClient("mongodb://192.168.70.133:27017");
            //獲取database
            var mydb = client.GetDatabase("myDb");
            //獲取collection
            var collection = mydb.GetCollection<Userinfo>("userinfos");
            var filter = Builders<Userinfo>.Filter;
            var sort = Builders<Userinfo>.Sort;
            List<Userinfo> userinfos = collection.Find(filter.Lt("age", 25))    //查詢年齡小於25歲的記錄
                                                 .Sort(sort.Descending("age"))  //按年齡進行倒序
                                         .ToList();
            //遍歷結果
            userinfos.ForEach(u => Console.WriteLine($"姓名:{u.name},年齡:{u.age},英文名:{u.ename.firstname} {u.ename.lastname}"));
            Console.ReadKey();
        }
    }
    /// <summary>
    /// 使用者類
    /// </summary>
    public class Userinfo
    {
        public int _id { get; set; }//id
        public string name { get; set; }//姓名
        public int age { get; set; }//年齡
        public int level { get; set; }//等級
        public Ename ename { get; set; }//英文名
        public string[] roles { get; set; }//角色
        public string address { get; set; }//地址
    }
    /// <summary>
    /// 英文名
    /// </summary>
    public class Ename
    {
        public string firstname { get; set; }
        public string lastname { get; set; }
    }

執行結果如下:

2 常用屬性

  上邊的栗子僅僅用了基本的自動化對映,使用基本的自動化對映時:類和Bson中的欄位必須嚴格一致(_id除外,可以自動對映到_id/id/Id),且Bson中的每一個欄位在實體類中都必須有一個對應的欄位,不然就會丟擲異常,這就造成我們可能要寫一個非常龐大的實體類,而且類中的欄位命名也要嚴格和Bson中的欄位一致。這些限制對我們開發來說是不能接受的,這裡我們採用mongoDriver中的一些屬性改進一下上邊的程式碼,如下:

    class Program
    {
        static void Main(string[] args)
        {//連線資料庫
            var client = new MongoClient("mongodb://192.168.70.133:27017");
            //獲取database
            var mydb = client.GetDatabase("myDb");
            //獲取collection
            var collection = mydb.GetCollection<Userinfo>("userinfos");

            var filter = Builders<Userinfo>.Filter;
            var sort = Builders<Userinfo>.Sort;
            List<Userinfo> userinfos = collection.Find(filter.Lt("age", 25))    //查詢年齡小於25歲的記錄
                                                 .Sort(sort.Descending("age"))  //按年齡進行倒序
                                         .ToList();
            //遍歷結果
            userinfos.ForEach(u =>
            {   
                Console.WriteLine($"編號:{u.userId},姓名:{u.name},年齡:{u.age},英文名:{u.ename?.ming} {u.ename?.xing},性別:{u.gender}");
                Console.WriteLine($"其他屬性:{u.otherprops}");
                Console.WriteLine();
            });
            
            Console.ReadKey();
        }
    }
    /// <summary>
    /// 使用者類
    /// </summary
    //[BsonIgnoreExtraElements]
    public class Userinfo
    {
        [BsonId]
        public int userId { get; set; }//id
        public string name { get; set; }//姓名
        public int age { get; set; }//年齡
        public Ename ename { get; set; }//英文名
        [BsonDefaultValue('')]
        public char gender { get; set; }
        [BsonIgnore]
        public string nickname { get; set; }//暱稱
        [BsonExtraElements]
        public BsonDocument otherprops { get; set; }//其他屬性
    }
    /// <summary>
    /// 英文名
    /// </summary>
    public class Ename
    {
        [BsonElement("firstname")]
        public string ming { get; set; }
        [BsonElement("lastname")]
        public string xing { get; set; }
    }

  執行結果如下:

這裡用到了幾個常用的屬性,作用如下:

  BsonId修飾的欄位對應BsonDocument中的_id;

  BsonDefaultValue(value)用於指定預設值;

  BsonIgnore表示不對映,即使BsonDocument中包含該欄位也不會賦值給屬性;

  BsonExtraElements修飾的欄位用於儲存沒有對映到類中的其他屬性;

  BsonElement可以指定修飾的屬性對映到BsonDocument中的哪個欄位,

還有一些其他的屬性,具體可以參考官方文件

3 MongoDB使用Linq查詢

  MongoDB的驅動支援Linq查詢,用法十分簡單,引用  usingMongoDB.Driver.Linq;  後,使用  collection.AsQueryable()  獲取IMongoQueryable<T>例項,然後就可以使用Linq對這個IMongoQueryable<T>進行查詢了。

  使用過EF的小夥伴應該都瞭解IQueryable+Linq的查詢預設不是將整個結果集立即載入到記憶體中,而是延遲載入的,即只有使用結果時(如 在執行First,Last,Single,Count,ToList等)才會將Linq轉換成Sql,在資料庫中執行查詢操作。類似的,在使用IMongoQueryable<T>+Linq進行查詢時預設也是延遲載入的,在需要使用查詢結果時,驅動會將Linq轉換成聚合管道命令(aggregation pipeline),如Linq中的Where被轉換成$watch,Join轉換為$lookup,Skip和Take轉換為$skip和$limit等等,然後在Mongodb中執行這些管道命令獲取結果,看一個栗子我們就會輕鬆地掌握了。

  首先新增一些測試資料:

//新增學生資料
db.students.insertMany([
    {"no":1, "stuName":"jack", "age":23, "classNo":1},
    {"no":2, "stuName":"tom", "age":20, "classNo":2},
    {"no":3, "stuName":"hanmeimei", "age":22, "classNo":1},
    {"no":4, "stuName":"lilei", "age":24, "classNo":2}
    ])
        
//新增班級資料
db.classxes.insertMany([
    {"no" : 1,"clsName" : "A班"},
    {"no" : 2,"clsName" : "B班"}
    ])

  這裡查詢了兩組資料:①基本查詢:查詢年齡大於22歲的學生;②連線查詢:查詢各個學生的學號、姓名、班級名。栗子比較簡單,直接看程式碼吧

        static void Main(string[] args)
        {
            //連線資料庫
            var client = new MongoClient("mongodb://192.168.70.133:27017");
            //獲取database
            var mydb = client.GetDatabase("myDb");
            //獲取collection
            var stuCollection = mydb.GetCollection<Student>("students");
            var clsCollection = mydb.GetCollection<Classx>("classes");
            //查詢年齡大於22的學生
            Console.WriteLine("-------------查詢年齡大於22的學生列表--------------");
            //1.query語法
            List<Student> stuList1 = (from stu in stuCollection.AsQueryable()
                        where stu.age > 22
                        select stu).ToList();
            //2.點語法
            List<Student> stuList2 = stuCollection.AsQueryable().Where(s => s.age > 22).ToList();
            stuList1.ForEach(stu => Console.WriteLine($"姓名:{stu?.stuName},  年齡:{stu?.age}"));
            Console.WriteLine();



            //表連線查詢,查詢各個學生的班級名
            Console.WriteLine("-------------表連線,查詢學生的班級名----------------");
            //1.query語法
            var result1 = from stu in stuCollection.AsQueryable()
                          join cls in clsCollection.AsQueryable()
                            on stu.classNo equals cls.no
                          select new { stuno = stu.no, stu.stuName, cls.clsName };
            //2.點語法
            var result2 = stuCollection.AsQueryable().Join(
                            clsCollection.AsQueryable(),
                            stu => stu.classNo,
                            cls => cls.no,
                            (stu, cls) => new { stuno=stu.no, stu.stuName, cls.clsName }
                         );
            //遍歷結果
            foreach (var item in result1)
            {
                Console.WriteLine($"學號:{item.stuno}, 姓名:{item.stuName}, 班級:{item.clsName}");
            }

            Console.ReadKey();
        }
    }
    /// <summary>
    /// 學生類
    /// </summary
    public class Student
    {
        public int no { get; set; }//學號
        public string stuName { get; set; }//姓名
        public int age { get; set; }//年齡
        public int classNo { get; set; }//班級編號
        [BsonExtraElements]
        public BsonDocument others { get; set; }
    }
    /// <summary>
    /// 班級類
    /// </summary>
    public class Classx
    {
        public int no { get; set; }//班級編號
        public string clsName { get; set; }//班級名
        [BsonExtraElements]
        public BsonDocument others { get; set; }
    }

  執行結果如下:

 

小結

  本篇簡單介紹了C#驅動mongoDB進行CRUD操作,C#驅動功能十分豐富,幾乎實現了所有的Mongo shell功能,這裡就不再過多介紹了,有興趣的小夥伴可以看看官方的文件。如果文中有錯誤的話,希望大家可以指出,我會及時修改,謝謝。

相關文章