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

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

相关推荐
码爸2 小时前
spark读mongodb
大数据·mongodb·spark
一个很帅的帅哥18 小时前
实现浏览器的下拉加载功能(类似知乎)
开发语言·javascript·mysql·mongodb·node.js·vue·express
JY_H20 小时前
MongoDB
数据库·mongodb
东城绝神1 天前
《Linux运维总结:基于ARM64+X86_64架构CPU使用docker-compose一键离线部署mongodb 7.0.14容器版副本集群》
linux·运维·mongodb·架构
香吧香2 天前
mongo 副本集rs 理解和使用小结
mongodb
香吧香2 天前
mongodb 中rs.stauts()命令参数解析
mongodb
青云交3 天前
大数据新视界 --大数据大厂之MongoDB与大数据:灵活文档数据库的应用场景
大数据·数据库·mongodb·非关系型数据库·文档存储·查询功能、数据处理·开发效率、应用场景、高可扩展性
香吧香4 天前
mongo集群同步数据异常,手动同步节点副本数据
mongodb
Navicat中国4 天前
Navicat 17 新特性 | 聚焦 MongoDB
数据库·sql·mongodb·信息可视化·nosql数据库·navicat
不剪发的Tony老师4 天前
MongoDB入门教程
数据库·mongodb