• 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 Transmissions { get; set; }
    
        public MyTaskEntity()
        {
            this.Transmissions = new List();
        }
    
        public MyTaskEntity(string orderNumber)
        {
            this.OrderNumber = orderNumber;
            this.Transmissions = new List();
        }
        
        ......
    }
    复制代码

    这里,我们以之前分享的一篇文章《在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
    {
        /// 
        /// Create indexes in MongoDB when startup
        /// NOTE: It'll skip creation when the indexes already exists.
        /// 
        public static void Initialize(IApplicationBuilder app)
        {
            var dbInstance = app.ApplicationServices.GetService();
            var logger = app.ApplicationServices.GetService>();
            var db = dbInstance.DatabaseClient.GetDatabase(dbInstance.DatabaseName);
    
            var collection = db.GetCollection("MyTasks");
    
            // Index definitions
            var indexKeysDefine = Builders.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
    {
        /// 
        /// Create indexes in MongoDB when startup
        /// NOTE: It'll skip creation when the indexes already exists.
        /// 
        public static void Initialize(IApplicationBuilder app)
        {
            var dbInstance = app.ApplicationServices.GetService();
            var logger = app.ApplicationServices.GetService>();
            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.Parse(indexCommand1));
                db.RunCommand(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

     

  • 相关阅读:
    gogs运行报“gogs“: cannot run executable found relative to current directory
    消息中间件篇之Kafka-数据清理机制
    openGauss学习笔记-75 openGauss 数据库管理-创建和管理序列
    软件测试需要学习什么?好学吗?需要学多久?到底是报班好还是自学好?
    帷幄匠心面试题 一面
    RK3399平台开发系列讲解(I/O篇)Linux最大文件数的限制机制
    怎么把视频压缩到最小?快把这些方法收好
    sql处理重复的列,更好理清分组和分区
    【正点原子Linux连载】第二十二章 AP3216C 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2
    面试官:你认为一个优秀的测试工程师需要具备哪些知识和经验?
  • 原文地址:https://www.cnblogs.com/edisonchou/p/auto-create-mongoindex-in-aspnet6.html