zoukankan      html  css  js  c++  java
  • 初识 MongoDB 和 .NET Core 入门


    昨天搭建完毕 MongoDB 集群 后,开始计划了解 MongoDB ,并引入使用场景,这里介绍一下学习过程中的一些笔记,帮助读者快速了解 MongoDB 并使用 C# 对其进行编码。

    浅入 MongoDB

    MonogoDB 是什么

    MongoDB 是 NoSQL 型数据库,主要特征是存储结构化数据,MongoDB 是基于分布式文件存储的开源数据库系统。

    结构化数据

    以往我们使用 Mysql、SqlServer 等数据库,数据都是一条条的。MongoDB 的结构化数据正是区别于这种列-行式的数据。

    结构化数据具有层级关系:

    例如:

    {
         name: "MongoDB",
         type: "database",
         count: 1,
         info: {
             x: 203,
             y: 102
         }
    }
    

    结构化数据

    MongoDB 与关系型数据库

    由于 MongoDB 中,没有表、行、列,因此初学 MongoDB 时可能会有困扰,这里给出一些 MongoDB 与 普通SQL数据库对应的术语。

    SQL术语/概念 MongoDB术语/概念 解释/说明
    database database 数据库
    table collection 数据库表/集合
    row document 数据记录行/文档
    column field 数据字段/域
    index index 索引
    table joins 非关系型数据库,表与表之间没关系
    primary key primary key 主键,MongoDB自动将_id字段设置为主键

    资料来源:https://www.runoob.com/mongodb/mongodb-databases-documents-collections.html

    MongoDB 入门命令

    使用 mongo 进入 MongoDB shell 后,可使用命令(相当于SQL)执行操作。

    注: MongoDB 中,有一个自动的 _id 字段,此字段 MongoDB 自动设置为主键并自动生成值。

    显示所有数据库(包含系统数据库):

    show dbs
    

    当前正在操作的数据库或集合:

    db
    

    连接到指定数据库:

    use {数据库名称}
    

    显示所有集合:

    show collections
    # 或
    show tables
    

    查看集合中的所有文档:

    # MyCollection 是集合名称
    db.getCollection("MyCollection").find()
    db.getCollection("MyCollection").find().limit(1000).skip(0)
    

    可能你不信,笔者百度了很久,第一页没找到一篇合适的友好的 "mongoDB 查看集合中的所有文档",特别是 CSDN 的垃圾文真的多。建议别瞎折腾了,去下一个 Navicat Premium,操作的时候,底部会提示所用的命令。

    使用工具查看MongoDB命令

    另外 MongoDB 有很多实用工具:https://docs.mongodb.com/tools/

    文档

    MongoDB 中的文档(Document)即关系型数据库中的一条记录(row)、一行数据。

    但, MongoDB 中,一个集合(Collection-Table)中,是不需要具有相同字段的。例如:

    A 文档:

    {
         name: "MongoDB",
         type: "database",
         count: 1,
         info: {
             x: 203,
             y: 102
         }
    }
    

    B 文档:

    {
         name: "MongoDB",
         typeName: "database",
         dataCount: 1,
         dataInfo: {
             m: 203,
             n: 102
         }
    }
    

    .NET Core 示例

    我们从一个基础模板开始。

    创建一个控制台程序,打开 Nuget 搜索并安装 MongoDB.Driver

                var client = new MongoClient("mongodb://{MongoDB}:27017");
                IMongoDatabase database = client.GetDatabase("Test");
    

    集合

    可以通过 CreateCollection()CreateCollectionAsync() 创建一个集合,跟普通数据库不同的是,创建集合时是不需要指定结构的,只需要指定名称即可:

    await database.CreateCollectionAsync("Test");
    

    获取集合

    GetCollection() 函数可以让我们获取到集合,如果集合不存在,则会自动创建。

    IMongoCollection<TDocument> GetCollection<TDocument>()
    

    由于同一个集合可以有不同字段和字段类型的文档,因此几个文档如果有所差别,是很难统一起来的,例如:

    集合的文档字段不同

    (N/A) 代表此文档没有这个字段;如果一个文档有 10 个字段,另一个文档有 8 个字段,但是两者的字段完全不同时,要合并起来来,就有 18 个字段了。很明显,不应该汇集在一起,而是应该使用强类型对其 ”归档“ 。

    创建两个类,分别为 Test1,Test2,其内容如下:

        public class Test1
        {
            public string Name { get; set; }
        }
    
        public class Test2
        {
            public string DataType { get; set; }
        }
    

    以两种文档类型获取集合:

                var collection1 = database.GetCollection<Test1>("Test");
                var collection2 = database.GetCollection<Test2>("Test");
    

    这个获取集合的意思是,获取此集合中这类格式的文档的操作能力。

    往集合中插入数据:

                collection1.InsertOne(new Test1 { Name = "Test1" });
                collection2.InsertOne(new Test2 { DataType = "Test2" });
    			// await collection.InsertOneAsync(object);
    

    启动,查看结果。

    InsertMany() 可以插入批量数据:

                Test1[] datas = new Test1[]
                {
                    new Test1 { Name = "Test1" }
                };
                collection1.InsertMany(datas);
    

    统计数量

    获取集合中所有的文档数:

    collection1.CountDocuments(new BsonDocument())
    // await collection1.CountDocumentsAsync(new BsonDocument());
    

    任意一个文档集合对象,使用 CountDocuments(new BsonDocument()) 都是获得此集合的所有文档数,而不是此类型的文档数。例如:

                var collection1 = database.GetCollection<Test1>("Test");
                collection1.CountDocuments(new BsonDocument())
    

    获取的并不是 Test1 类型的文档数量,而是整个集合所有文档的数量。

    原因是,CountDocuments() 是一个过滤器函数,可以使用指定条件来筛选符合条件的文档的数量。指定条件后面会介绍。

    查询

    MongoDB 的查询并不像 LInq 中的表达式,基础了 IEnumerableIEnumerable<T> 接口,因此驱动没有 WhereSelect 这种表达式的查询方法。

    Find() 函数是查询函数,里面可以添加丰富的表达式,来筛选文档,当数据加载到本地内存后,即可使用丰富的表达式。

    BsonDocument 是一个类型,代表了要查询的文档筛选条件,如果 BsonDocument 对象没有添加任何属性,则代码没有筛选参数,则默认所有文档都符号条件。

    我们把 Test1 和 Test2 类型,都加上一个属性:

            public ObjectId _id { get; set; }
    

    不然会报格式化错误:System.FormatException

    如何序列化文档

    document 是文档对象, JsonSerializer 是 System.Text.Json 的静态类。

    Console.WriteLine(JsonSerializer.Serialize(document));
    

    查询第一条记录

    var document = collection1.Find(new BsonDocument()).FirstOrDefault();
    

    不加条件可能导致的问题

    以下代码会导致程序报错:

                var documents = await collection1.Find(new BsonDocument()).ToListAsync();
                foreach(var item in documents)
                {
                    Console.WriteLine(JsonSerializer.Serialize(item));
                }
    

    因为 collection1 是标记为 Test1 的文档集合;但是 .Find(new BsonDocument()) 是查询集合中的所有文档,因此获取到 Test2。

    但是 Test2 是不能转为 Test1 的,因此,会导致程序报错。

    查看所有文档

    var documents = collection1.Find(new BsonDocument()).ToList();
    var documents = await collection1.Find(new BsonDocument()).ToListAsync();
    

    前面已经说过,如果集合中存在其它格式的文档,获取全部文档时,因为 Test2 跟 Test1 没任何关系,会导致 MongoDB.Driver 报错。

    如果文档数量比较大,要使用异步的 ForEachAsync() 查询,其原理是 回调。

                List<Test1> tests = new List<Test1>();
                Action<Test1> action = item =>
                {
                    tests.Add(item);
                    Console.WriteLine(JsonSerializer.Serialize(item));
                };
    
                await collection1.Find(new BsonDocument()).ForEachAsync(action);
    

    查询结束

    使用 Find() 以及后续函数查询后,要结束查询(延迟加载),可以使用 ToCursor() 函数结束,程序会立即开始查询并将数据返回内存。

    转换查询

    使用 ToEnumerable() 可以使用 Linq 来查询文档。

    var list = collection1.Find(new BsonDocument()).ToCursor().ToEnumerable();
    

    过滤器

    前面我们查询的时候都使用 .Find(new BsonDocument())BsonDocument 是过滤器对象,里面存储了过滤的规则,但是我们不能直接设置 new BsonDocument() 中的属性,而是使用构建器FilterDefinitionBuilder对象,而此对象可以通过 MongoDB.Driver.Builders<TDocument>.Filter 创建 。

    假设有以下数据集(文档):

    5f8bdf88e63d14cb5f01dd85	小明	19
    5f8bdf88e63d14cb5f01dd86	小红	20
    5f8bdf88e63d14cb5f01dd87	小张	16
    5f8bdf88e63d14cb5f01dd88	小小	17
        
    # -----插入数据的代码-----
        public class Test
        {
            public ObjectId _id { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
        }
    
                var datas = new Test[]
                {
                    new Test{ Name="小明",Age=19},
                    new Test{ Name="小红",Age=20},
                    new Test{ Name="小张",Age=16},
                    new Test{ Name="小小",Age=17}
                };
    
                collection.InsertMany(datas);
    

    使用构建器:

    FilterDefinition<Test> filter = Builders<Test>.Filter
    

    查询 Age 大于 18 的文档:

    FilterDefinition<Test> filter = filterBuilder.Where(item => item.Age >= 18);
    

    获取结果:

    Test[] documents = collection.Find(filter).ToEnumerable<Test>().ToArray();
    

    过滤器还有 Gt()In()Lte() 等非 Linq 的函数,需要查看文档学习。

    Builders<TDocument>

    Builders<TDocument> 除了能够生成过滤构建器,还有其它几种构建器:

    		// 条件过滤
            public static FilterDefinitionBuilder<TDocument> Filter { get; }
    
    		// 索引过滤
            public static IndexKeysDefinitionBuilder<TDocument> IndexKeys { get; }
    
    		// 映射器,相当于使用 Linq 的 .Select() 查询自己只需要的字段
            public static ProjectionDefinitionBuilder<TDocument> Projection { get; }
    
    		// 排序,创建排序规则,如工具年龄排序
            public static SortDefinitionBuilder<TDocument> Sort { get; }
    
    		// 更新,更新某些字段的值等
            public static UpdateDefinitionBuilder<TDocument> Update { get; }
    

    详细请参考 https://mongodb.github.io/mongo-csharp-driver/2.10/reference/driver/definitions/#projections

    名称映射

    由于 MongoDB 区分字段的大小写,文档的字段一般使用驼峰命名法,首字母小写,而 C# 字段属性首字母是 大小开头的,因此需要不同名称对应起来。

    可以使用 BsonElement 特性来设置映射的名称。

    class Person
    {
        [BsonElement("fn")]
        public string FirstName { get; set; }
    
        [BsonElement("ln")]
        public string LastName { get; set; }
    }
    

    以上就是 MongoDB 的初入门知识,但是使用了 MongoDB 有什么好处?可以参考阿里云的这篇文章:https://developer.aliyun.com/article/64352

    整理场景如下:

    • 存储应用程序日志。日志结构化,查找方便,可以导出其它格式和二次利用。

    • 增加字段不需要改动表结构,灵活变更。

    • 支持 json 格式导入;类似 json 的数据结构;能够很容易还原对象的属性,一次性存储数据;如果使用传统数据库,则需要建立多个表并设置主键外界关系。

    • 集群。分布式集群海量数据,容易拓展;故障转移保证服务可用;

    • 解决分布式文件存储需求。

    • 索引方式灵活。

    • ... ...

  • 相关阅读:
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车按键启动和蜂鸣器报警
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    asp中设置session过期时间方法总结
    asp中设置session过期时间方法总结
    ASP.NET关于Session_End触发与否的问题
  • 原文地址:https://www.cnblogs.com/whuanle/p/13835306.html
Copyright © 2011-2022 走看看