大家好,我是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

作者:周旭龙

出处:https://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

ASP.NET 6启动时自动创建MongoDB索引的更多相关文章

  1. 小白在 Eclipse如何避免启动时自动building workspace和validating

    问题: Eclipse启动时会出现如下的情况(时间比较长): 原因所在: Validating 意为验证,validating... 逐个的检查每一个文件,Eclipse在启动时自动验证代码和创建wo ...

  2. Code First 迁移----官方 应用程序启动时自动升级(MigrateDatabaseToLatestVersion 初始值设定项)

    Code First 迁移 如果使用的是 Code First 工作流,推荐使用 Code First 迁移改进应用程序的数据库架构. 迁移提供一组允许以下操作的工具: 创建可用于 EF 模型的初始数 ...

  3. 如何在.NET程序崩溃时自动创建Dump?

    今天在浏览张队转载文章的留言时,遇到一个读者问了这样的问题,如下图所示: 首先能明确的一点是"程序崩溃退出了是不能用常规的方式dump的",因为整个进程树都已经退出.现场已经无法使 ...

  4. Tomcat启动时自动加载Servlet

    1.想做一个服务启动时自动启动一不停止的获取订阅功能 2.之前是做一个Jsp页面请求servlet来触发方法 3.现在实现Tomcat启动时自动加载Servlet 1.Tomcat中启动Servlet ...

  5. 如何让openvpn在windows启动时自动加载

    在非常需要vpn的人群中,他们几乎一整天都连接着vpn,但是每次开机都要连接vpn的过程有时候比较繁琐对于新手而言.这篇文章主要是说明如何在windows启动时自动加载openvpn自动连接,该教程适 ...

  6. [转]在BBB启动时自动加载dtbo(或执行脚本、运行程序)

    启动时自动加载dtbo,实际上就是做了一个cape.官方推荐的方法是用eeprom来实现,请参考我的博文<为BBB制作专属自己的cape(一)>和<为BBB制作专属自己的cape(四 ...

  7. 查询事件状态,mysql查看事件是否开启,设置启动时自动开启方法

    1.查看事件是否开启 SHOW VARIABLES LIKE 'event_scheduler' 2.设置当前事件开启 SET GLOBAL event_scheduler = 1; 或 SET GL ...

  8. SAS启动时自动执行代码

    有时候我们希望SAS启动时自动执行已经编写好的程序,可以按照以下方法实现: 首先正常打开SAS,编写我们想要让SAS启动时自动执行的代码,例如获取桌面文件夹路径,以便在其他程序中引用这个路径. pro ...

  9. 让docker中的mysql启动时自动执行sql文件

    本文提要 本文目的不仅仅是创建一个MySQL的镜像,而是在其基础上再实现启动过程中自动导入数据及数据库用户的权限设置,并且在新创建出来的容器里自动启动MySQL服务接受外部连接,主要是通过Docker ...

  10. ssh整合思想 Spring与Hibernate的整合 项目在服务器启动则自动创建数据库表

    Spring整合Hibernate Spring的Web项目中,web.xml文件会自动加载,以出现欢迎首页.也可以在这个文件中对Spring的配置文件进行监听,自启动配置文件, 以及之前Struts ...

随机推荐

  1. MySQL锁表解锁表

    CREATE TABLE t1 ( id int(11) NOT NULL, val varchar(10) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoD ...

  2. 全球唯一云厂商!华为云高分入选2023Gartner Peer Insights™云数据库管理系统“客户之选”

    本文分享自华为云社区<华为云高分入选2023Gartner Peer Insights云数据库管理系统"客户之选">,作者:GaussDB 数据库 . 近日,Gartn ...

  3. 精选Golang高频面试题和答案汇总

    大家好,我是阳哥. 之前写的< GO必知必会面试题汇总>,已经阅读破万,收藏230+. 也欢迎大家收藏.转发本文. 这篇文章给大家整理了17道Go语言高频面试题和答案详解,每道题都给出了代 ...

  4. asp登录认证,记录最后一次登录时间,写入数据库代码

    最近开发了一个船员招聘网的程序,但是由于部分功能需要配合ASP代码才能使用,所以就发现以前写的这个asp登录认证代码,今天就将他公布一下. <!--#include file="con ...

  5. 谷歌语法的基础知识&FOFA

    谷歌语法 谷歌语法基础符号: "xxx":表示完全匹配,即关键字不能分开,顺序也不能变 +:"xxx"+www.baidu.com  搜索xxx与baidu.c ...

  6. win10安装mysql时提示错误:mysqld: Can't change dir to 'C: oftware\mysql\data\' (Errcode: 2 - No such file or directory)

    win10安装解压版mysql时,提示错误: 2019-10-22 09:02:00 2004 [ERROR] Can't find messagefile 'C:\WINDOWS\system32\ ...

  7. web系统字典统一中文翻译问题

    几乎每个web系统都离不开各种状态码.订单新建,待支付,未支付,已支付,待发货. 消息已读未读,任务待标记待审批已审批待流转已完成未完成.等等. 复杂一点的,会有多级状态码. 状态码超出3个的,一般都 ...

  8. MYSQL中JSON类型介绍

    1 json对象的介绍 在mysql未支持json数据类型时,我们通常使用varchar.blob或text的数据类型存储json字符串,对mysql来说,用户插入的数据只是序列化后的一个普通的字符串 ...

  9. Singleton Pattern 单例模式简介与 C# 示例【创建型】【设计模式来了】

    〇.简介 1.什么是单例模式? 一句话解释:   单一的类,只能自己来创建唯一的一个对象. 单例模式(Singleton Pattern)是日常开发中最简单的设计模式之一.这种类型的设计模式属于创建型 ...

  10. zookeeper运维常用指令

    zkServer.sh ./zkServer.sh start:启动zookeeper ./zkServer.sh stop:停止zookeeper ./zkServer.sh status:查看zo ...