1

ASP.NET 6启动时自动创建MongoDB索引 - EdisonZhou

 11 months ago
source link: https://www.cnblogs.com/edisonchou/p/auto-create-mongoindex-in-aspnet6.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

ASP.NET 6启动时自动创建MongoDB索引

大家好,我是Edison。

最近,在使用MongoDB时,碰到这样的一个需求:针对某个Collection手动在开发环境创建了索引,但在测试环境和生产环境不想再手动操作了,于是就想着通过代码的方式在ASP.NET 6应用启动时自动创建。

索引本质上是树,最小的值在最左边的叶子上,最大的值在最右边的叶子上,使用索引可以提高查询速度(而不用全表扫描),也可以预防脏数据的插入(如唯一索引)。索引既支持普通字段,也支持内嵌文档中某个键和数组元素进行索引。

381412-20230927180329467-1750741942.png

在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

o_200902144330EdisonTalk-Footer.jpg

作者:周旭龙

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK