初识 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 有很多实用工具: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 中的表达式,基础了 IEnumerable或 IEnumerable<T> 接口,因此驱动没有 Where、Select 这种表达式的查询方法。
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 的数据结构;能够很容易还原对象的属性,一次性存储数据;如果使用传统数据库,则需要建立多个表并设置主键外界关系。 
- 集群。分布式集群海量数据,容易拓展;故障转移保证服务可用; 
- 解决分布式文件存储需求。 
- 索引方式灵活。 
- ... ... 
初识 MongoDB 和 .NET Core 入门的更多相关文章
- 孤荷凌寒自学python第五十五天初识MongoDb数据库
		孤荷凌寒自学python第五十五天第一天初识MongoDb数据库 (完整学习过程屏幕记录视频地址在文末) 大家好,2019年新年快乐! 本来我想的是借新年第一天开始,正式尝试学习爬虫,结果今天偶然发现 ... 
- Asp.Net SignalR 使用记录  技术回炉重造-总纲  动态类型dynamic转换为特定类型T的方案   通过对象方法获取委托_C#反射获取委托_  .net core入门-跨域访问配置
		Asp.Net SignalR 使用记录 工作上遇到一个推送消息的功能的实现.本着面向百度编程的思想.网上百度了一大堆.主要的实现方式是原生的WebSocket,和SignalR,再次写一个关于A ... 
- CentOS开发ASP.NET Core入门教程
		作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9891346.html 因为之前一直没怎么玩过CentOS,大多数时间都是使用Win10进行开发,然后程序 ... 
- ASP.NET Core 入门教程 10、ASP.NET Core 日志记录(NLog)入门
		一.前言 1.本教程主要内容 ASP.NET Core + 内置日志组件记录控制台日志 ASP.NET Core + NLog 按天记录本地日志 ASP.NET Core + NLog 将日志按自定义 ... 
- MongoDB 极简实践入门
		原作者StevenSLXie; 原链接(https://github.com/StevenSLXie/Tutorials-for-Web-Developers/blob/master/MongoDB% ... 
- ASP.NET Core入门(一)
		大家好,很荣幸您点了开此篇文章,和我一起来学习ASP.NET Core,此篇文字为<ASP.NET Core入门>系列中的第一篇,本系列将以一个博客系统为例,从第一行代码,到系统发布上线( ... 
- 【翻译】ASP.NET Core 入门
		ASP.NET Core 入门 原文地址:Introduction to ASP.NET Core 译文地址:asp.net core 简介 翻译:ganqiyin ... 
- net Core 入门实战
		Asp.net Core 入门实战 Asp.Net Core 是开源,跨平台,模块化,快速而简单的Web框架. Asp.net Core官网的一个源码合集,方便一次性Clone 目录 快速入门 安 ... 
- MongoDB最简单的入门教程之二 使用nodejs访问MongoDB
		在前一篇教程 MongoDB最简单的入门教程之一 环境搭建 里,我们已经完成了MongoDB的环境搭建. 在localhost:27017的服务器上,在数据库admin下面创建了一个名为person的 ... 
随机推荐
- ES6语法笔记
			迭代器 // log let arr = ['一', '二', '三'] let iter = arr[Symbol.iterator]() console.log(iter.next()) cons ... 
- Android组件化 + MVP + MVVM
			前言 组件化和插件化已经提出了很久了,到现在也是比较稳定的一种架构方案了,在三年前,组件化和插件提出来没多久,前公司就已经在项目中使用了,只是当时还只是菜鸟,没有资格参与到架构的建设中,只是在大佬搭好 ... 
- oracle之同义词
			同义词 从字面上理解就是别名的意思,和视图的功能类似.就是一种映射关系. 14.1 私有同义词; 一般是普通用户自己建立的同义词,创建者需要create synonym 权限. sys:SQL> ... 
- MYsql添加用户、赋予权限
			1.创建新用户 CREATE USER 'admin'@'%' IDENTIFIED BY '123456'; '%' 表示可以远程登录访问.操作 ‘localhost’ 表示只能本地登录访问.操作2 ... 
- 再见了SpringMVC!这个框架有点厉害,甚至干掉了Servlet!
			# 前言 对 Java 开发者来说, Spring 发布 5.0 正式版,而新版 Spring 的一大特色,就是 Reactive Web 方案 Web Flux,这是用来替代 Spring Web ... 
- rest_framework五大模块
			面向对象封装 面向对象封装导入 # 1.将子类共有的方法抽离形成父类方法 # 2.子类使用共有方法,使用的是父类方法 # 3.共有方法中的资源,在子类使用方法时,获取的是子类资源 class MyCl ... 
- 【转】Locust性能-零基础入门系列(2) -重写wait_time
			在虚拟模拟的时候,可能对等待时间有更高的要求,比如假如有这么一个场景要求:某任务要求每被执行1次,那么下次的等待时间就1秒钟.这种情况,是可以实现的,这也就体现了Locust的灵活性.可编程性,很多比 ... 
- 刷题[GKCTF2020]
			[GKCTF2020]CheckIN 解题思路 打开直接是源码: <title>Check_In</title> <?php highlight_file(__FILE_ ... 
- 深入理解TypeScript——第一章:上手篇
			怎么定义TypeScript呢? TypeScript是一个工具 是一个编译器 编译代码 TypeScript,通过它的能力,默认使用tsc命令,可以根据.ts为后缀名的文件生成一个新的js文件 2. ... 
- c++11 新特性实战 (一):多线程操作
			c++11多线程操作 线程 thread int main() { thread t1(Test1); t1.join(); thread t2(Test2); t2.join(); thread t ... 
