ASP.NET 6启动时自动创建MongoDB索引
大家好,我是Edison。
最近,在使用MongoDB时,碰到这样的一个需求:针对某个Collection手动在开发环境创建了索引,但在测试环境和生产环境不想再手动操作了,于是就想着通过代码的方式在ASP.NET 6应用启动时自动创建。
背景知识
索引本质上是树,最小的值在最左边的叶子上,最大的值在最右边的叶子上,使用索引可以提高查询速度(而不用全表扫描),也可以预防脏数据的插入(如唯一索引)。索引既支持普通字段,也支持内嵌文档中某个键和数组元素进行索引。

在MongoDB中可以创建的索引类型:
唯一索引 unique:保证数据的唯一不重复
稀疏索引 sparse
复合索引:用于提高查询速度
TTL 索引 : 设置文档的缓存时间,时间到了会自动删除掉
全文索引:便于大文本查询(如概要、文章等长文本)
二维平面索引:便于2d平面查询
地理空间索引:便于地理查询
通过Mongo Shell管理索引:
// 创建索引
db.collection.createIndex(keys, options);
// 查询索引
db.collection.getIndexes(filter);
// 删除索引
db.collection.dropIndex("IndexName");
// 删除所有索引
db.collection.dropIndexes()
// explain 查看查询是否走索引
// "stage" : "COLLSCAN", 表示全集合扫描
// "stage" : "IXSCAN" ,基于索引的扫描
db.collection.find(query,options).explain(options)
准备工作
假设我们有一个Entity定义如下:
[Table("MyTasks")]
public class MyTaskEntity : IEntity
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public ObjectId Id { get; set; }
public string OrderNumber { get; set; }
public List<TransmissionEntity> Transmissions { get; set; }
public DispatchTaskEntity()
{
this.Transmissions = new List<TransmissionEntity>();
}
public DispatchTaskEntity(string orderNumber)
{
this.OrderNumber = orderNumber;
this.Transmissions = new List<TransmissionEntity>();
}
......
}
这里,我们以之前分享的一篇文章《在ASP.NET 6中使用工作单元操作MongoDB》为基础,不熟悉的朋友可以先看看这篇文章。
下面,我们将使用基于上面提到的那篇文章中的 EDT.MongoProxy组件中 的内容 MongoDbConection,这是一个包裹MongoClient的单例对象:
public class MongoDbConnection : IMongoDbConnection
{
public IMongoClient DatabaseClient { get; }
public string DatabaseName { get; } public MongoDbConnection(MongoDatabaseConfigs configs, IConfiguration configuration)
{
DatabaseClient = new MongoClient(configs.GetMongoClientSettings(configuration));
DatabaseName = configs.DatabaseName;
}
}
方式一:使用Builders.IndexKeys
这里创建一个静态类AppDbContext用于进行MongoDB索引创建,假设我们需要创建一个针对OrderNumber字段升序排列的唯一索引,那么创建的代码如下所示:
public static class AppDbContext
{
/// <summary>
/// Create indexes in MongoDB when startup
/// NOTE: It'll skip creation when the indexes already exists.
/// </summary>
public static void Initialize(IApplicationBuilder app)
{
var dbInstance = app.ApplicationServices.GetService<IMongoDbConnection>();
var logger = app.ApplicationServices.GetService<ILogger<MongoRepository>>();
var db = dbInstance.DatabaseClient.GetDatabase(dbInstance.DatabaseName); var collection = db.GetCollection("MyTasks"); // Index definitions
var indexKeysDefine = Builders<MyTaskEntity>.IndexKeys.Ascending(indexKey => indexKey.OrderNumber); // Create indexes by RunCommand
try
{
await collection.Indexes.CreateOneAsync(new CreateIndexModel(indexKeysDefine));
}
catch (Exception ex)
{
logger.LogError(ex, "{service}.{method} - throws an exception when creating indexes in database",
nameof(AppDbContext), nameof(Initialize));
}
}
}
使用Builders.IndexKeys可以方便快速的声明索引,并且它只会在对应索引不存在的时候创建,已存在时则会跳过。
但是如果你想要给集合字段的某个字段声明索引,则不太容易实现。这个时候,你可以考虑方式二。
方式二:使用RunCommand
这里我们修改一下上面AppDbContext中Initialize方法,通过构造两个Mongo Shell命令的方式来创建索引。
与上面不同的是,这里我们还针对集合类型的几个常用查询字段创建了一个组合索引,代码如下所示:
public static class AppDbContext
{
/// <summary>
/// Create indexes in MongoDB when startup
/// NOTE: It'll skip creation when the indexes already exists.
/// </summary>
public static void Initialize(IApplicationBuilder app)
{
var dbInstance = app.ApplicationServices.GetService<IMongoDbConnection>();
var logger = app.ApplicationServices.GetService<ILogger<MongoRepository>>();
var db = dbInstance.DatabaseClient.GetDatabase(dbInstance.DatabaseName);
// Index definitions
var indexCommand1 = @"{ createIndexes: 'MyTasks', indexes: [ { key: { 'OrderNumber': 1 }, name:'Idx_OrderNumber', unique: true } ] }";
var indexCommand2 = @"{ createIndexes: 'MyTasks', indexes: [ { key: { 'Transmissions.Type': 1, 'Transmissions.Status':1, 'Transmissions.Retries':1 }, name:'Idx_Transmission_TypeStatusRetries', unique: false } ] }"; // Create indexes by RunCommand
try
{
db.RunCommand<BsonDocument>(BsonDocument.Parse(indexCommand1));
db.RunCommand<BsonDocument>(BsonDocument.Parse(indexCommand2));
}
catch (Exception ex)
{
logger.LogError(ex, "{service}.{method} - throws an exception when creating indexes in database",
nameof(AppDbContext), nameof(Initialize));
}
}
}
在Program.cs中使用
这里我们仅仅需要在Program.cs中添加以下语句即可实现在ASP.NET 6应用启动时创建MongoDB索引啦:
......
AppDbContext.Initialize(app);
......
小结
本文我们了解了如何在ASP.NET 6应用启动时实现自动创建MongoDB的索引,相信会对你在ASP.NET 6中使用MongoDB有一定帮助!
参考资料
Kevin Smith,《Creating MongoDB indexes in ASP.NET Core 3.1》
TheCodeBuzz,《Create MongoDB indexes in C#.NET Part 1》
TheCodeBuzz,《Create MongoDB indexes in C#.NET Part 2》

ASP.NET 6启动时自动创建MongoDB索引的更多相关文章
- 小白在 Eclipse如何避免启动时自动building workspace和validating
问题: Eclipse启动时会出现如下的情况(时间比较长): 原因所在: Validating 意为验证,validating... 逐个的检查每一个文件,Eclipse在启动时自动验证代码和创建wo ...
- Code First 迁移----官方 应用程序启动时自动升级(MigrateDatabaseToLatestVersion 初始值设定项)
Code First 迁移 如果使用的是 Code First 工作流,推荐使用 Code First 迁移改进应用程序的数据库架构. 迁移提供一组允许以下操作的工具: 创建可用于 EF 模型的初始数 ...
- 如何在.NET程序崩溃时自动创建Dump?
今天在浏览张队转载文章的留言时,遇到一个读者问了这样的问题,如下图所示: 首先能明确的一点是"程序崩溃退出了是不能用常规的方式dump的",因为整个进程树都已经退出.现场已经无法使 ...
- Tomcat启动时自动加载Servlet
1.想做一个服务启动时自动启动一不停止的获取订阅功能 2.之前是做一个Jsp页面请求servlet来触发方法 3.现在实现Tomcat启动时自动加载Servlet 1.Tomcat中启动Servlet ...
- 如何让openvpn在windows启动时自动加载
在非常需要vpn的人群中,他们几乎一整天都连接着vpn,但是每次开机都要连接vpn的过程有时候比较繁琐对于新手而言.这篇文章主要是说明如何在windows启动时自动加载openvpn自动连接,该教程适 ...
- [转]在BBB启动时自动加载dtbo(或执行脚本、运行程序)
启动时自动加载dtbo,实际上就是做了一个cape.官方推荐的方法是用eeprom来实现,请参考我的博文<为BBB制作专属自己的cape(一)>和<为BBB制作专属自己的cape(四 ...
- 查询事件状态,mysql查看事件是否开启,设置启动时自动开启方法
1.查看事件是否开启 SHOW VARIABLES LIKE 'event_scheduler' 2.设置当前事件开启 SET GLOBAL event_scheduler = 1; 或 SET GL ...
- SAS启动时自动执行代码
有时候我们希望SAS启动时自动执行已经编写好的程序,可以按照以下方法实现: 首先正常打开SAS,编写我们想要让SAS启动时自动执行的代码,例如获取桌面文件夹路径,以便在其他程序中引用这个路径. pro ...
- 让docker中的mysql启动时自动执行sql文件
本文提要 本文目的不仅仅是创建一个MySQL的镜像,而是在其基础上再实现启动过程中自动导入数据及数据库用户的权限设置,并且在新创建出来的容器里自动启动MySQL服务接受外部连接,主要是通过Docker ...
- ssh整合思想 Spring与Hibernate的整合 项目在服务器启动则自动创建数据库表
Spring整合Hibernate Spring的Web项目中,web.xml文件会自动加载,以出现欢迎首页.也可以在这个文件中对Spring的配置文件进行监听,自启动配置文件, 以及之前Struts ...
随机推荐
- 从零玩转系列之微信支付实战PC端接口搭建
一.前言 halo各位大佬很久没更新了最近在搞微信支付,因商户号审核了我半个月和小程序认证也找了资料并且将商户号和小程序进行关联,至此微信支付Native支付完成.此篇文章过长我将分几个阶段的文章发布 ...
- 【webpack系列】从核心概念到上手配置
前言 作为前端开发者,相信大家或多或少都接触过webpack,现如今webpack已经渗透在了前端的各个方面,所以我们有必要来了解并学习webpack,webpack 是一种用于构建 JavaScri ...
- 【C++ Primer】第二章(2 ~ 6节)
变量 变量提供一个具名的.可供程序操作的存储空间. C++中变量和对象一般可以互换使用. 变量定义(define) 定义形式:类型说明符(type specifier) + 一个或多个变量名组成的列表 ...
- 【了解LLM】—— LLM&& SD 基本概念
本文地址:https://www.cnblogs.com/wanger-sjtu/p/17417312.html Causual LM 这里以llama模型为例,通常在执行用户输入之前会有一个[[文章 ...
- Java 访问控制权限修饰符
1.访问控制权限修饰符来控制元素的访问范围 2.访问控制权限修饰符包括: public 表示公开的,任何位置都可以可以访问 protected 同包,子类 缺省 同包 private 表示私有的,只能 ...
- 自研ORM (匠心之作)
Fast Framework 作者 Mr-zhong 代码改变世界.... 一.前言 Fast Framework 基于NET6.0 封装的轻量级 ORM 框架 支持多种数据库 SqlServer O ...
- [数据分析与可视化] 基于plottable库绘制精美表格
plottable是一个Python库,用于在matplotlib中绘制精美定制的图形表格.plottable的官方仓库地址为:plottable.本文主要参考其官方文档,plottable的官方文档 ...
- Django基本数据库操作
Django基本数据库操作 @ 目录 Django基本数据库操作 内容一:基本数据库配置 内容二:ORM基本操作 内容一:基本数据库配置 Django是一个流行的Python Web框架,它可以 ...
- Mysql高级1-存储引擎
一.Mysql体系结构 1.1.连接层 最上层是一个客户端和链接服务,主要完成一些类似于链接处理,授权认证,及相关的安全方案,服务器也会为安全接入的而每个客户端验证它所具有的操作权限 1.2.服务层 ...
- 2021-7-12 VUE的生命周期
挂载: beforeCreate created beforeMount mounted:el挂载到实例上时运行 更新: beforeUpdate updated 销毁: beforeDestory ...