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


作者:周旭龙

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

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

相关推荐
爬山算法11 小时前
MongoDB(80)如何在MongoDB中使用多文档事务?
数据库·python·mongodb
爬山算法16 小时前
MongoDB(79)事务的特性是什么?
数据库·python·mongodb
知识分享小能手1 天前
MongoDB入门学习教程,从入门到精通,MongoDB 副本集管理完全指南(13)
数据库·学习·mongodb
爬山算法2 天前
MongoDB(78)什么是MongoDB的事务?
数据库·mongodb
知识分享小能手2 天前
MongoDB入门学习教程,从入门到精通,MongoDB从应用程序连接副本集(12)
数据库·学习·mongodb
你才是臭弟弟2 天前
MongoDB Community Server (社区版)安装流程
数据库·mongodb
你才是臭弟弟2 天前
MongoDB介绍
数据库·mongodb
你才是臭弟弟2 天前
MongoDB 基本SQL操作
sql·mongodb·oracle
爬山算法2 天前
MongoDB(71)如何启用MongoDB身份验证?
数据库·mongodb·oracle
无风听海2 天前
.NET10之HttpContext.RequestServices 深入解析
.net·asp.net core