大家好,我是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. 园子的商业化努力-行行AI人才培养「常青藤计划」

    各位园子的小伙伴: 感谢大家长期对园子的支持,AI大模型出现之后,各行各业都在积极思考如何应对,如何把业务场景和AI结合.在这个过程中,AI人才缺乏是最核心的问题. 基于此,园子打算在AI人才培养方面 ...

  2. 【了解LLM】——LoRA

    本文地址:https://www.cnblogs.com/wanger-sjtu/p/17470327.html 论文链接:link code: github 什么是LoRA LoRA,英文全称Low ...

  3. 6大数据实战系列-sparkSql实战

    sparkSql两个最重要的类SqlContext.DataFrame,DataFrame功能强大,能够与rdd互转换.支持sql操作如sql().where.order.join.groupBy.l ...

  4. 如何在.net6webapi中记录每次接口请求的日志

    为什么在软件设计中一定要有日志系统? 在软件设计中日志模块是必不可少的一部分,可以帮助开发人员更好的了解程序的运行情况,提高软件的可靠性,安全性和性能,日志通常能帮我们解决如下问题: 调试和故障排查: ...

  5. CodeTON Round 5 (Div. 1 + Div. 2, Rated, Prizes!) A-E

    比赛链接 A 代码 #include <bits/stdc++.h> using namespace std; using ll = long long; bool solve() { i ...

  6. 【VUE】 文件预览

    [VUE] 文件预览 上传前预览 word文档:docx.doc 核心代码 import {renderAsync} from "docx-preview"; /** * 渲染do ...

  7. QOJ 6504. CCPC Final 2022 D Flower's Land 2题解

    QOJ 6504. CCPC Final 2022 D Flower's Land 2题解 题意简述 给你一个只含 \(0,1,2\) 的序列,相邻两个相同的数字可以直接消掉. 询问包含两种 区间所有 ...

  8. ListView选中获取数据并弹出菜单项

    前言 作为一名Android小白,我在编写过程中,使用ListView列表,想要使用他来完成长按弹出菜单选项,并且还要进行事件操作,经过百度编程的经历后,终于成功完成.在此附上这块比较完整的代码,理论 ...

  9. 【技术积累】Linux中的命令行【理论篇】【一】

    7z命令 命令介绍 7z命令是Linux系统中的一个压缩和解压缩工具,它可以用来创建.压缩和解压缩7z格式的文件.7z是一种高压缩率的文件格式,通常比其他常见的压缩格式(如zip和gzip)具有更高的 ...

  10. 在Volo.Abp微服务中使用SignalR

    假设需要通过SignalR发送消息通知,并在前端接收消息通知的功能 创建SignalR服务 在项目中引用 abp add-package Volo.Abp.AspNetCore.SignalR 在Mo ...