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

asp,net,启动时,自动,创建,mongodb,索引 · 浏览次数 : 41

小编点评

**方法一:使用 Builders.IndexKeys** ```csharp 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, "Throws an exception when creating indexes in database"); } } ``` **方法二:使用 RunCommand** ```csharp public static void Initialize(IApplicationBuilder app) { var dbInstance = app.ApplicationServices.GetService(); var logger = app.ApplicationServices.GetService>(); var db = dbInstance.DatabaseClient.GetDatabase(dbInstance.DatabaseName); // Create indexes using RunCommand db.RunCommand("createIndexes", new CreateIndexesCommand { IndexName = "Idx_OrderNumber", Indexes = new BsonDocument[] { new BsonDocument("OrderNumber", 1, BsonType.Int32), }, }); db.RunCommand("createIndexes", new CreateIndexesCommand { IndexName = "Idx_Transmission_TypeStatusRetries", Indexes = new BsonDocument[] { new BsonDocument("Transmissions.Type", 1, BsonType.Int32), new BsonDocument("Transmissions.Status", 1, BsonType.Int32), new BsonDocument("Transmissions.Retries", 1, BsonType.Int32), }, }); } ``` **注意:** * 方法一使用 Builders.IndexKeys 创建索引,其中键是 OrderNumber。 * 方法二使用 RunCommand 创建索引,其中键是 OrderNumber、Transmission Type 和 Retry。 * 在使用 RunCommand 创建索引之前,请确保您的 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 MyTaskEntity()
    {
        this.Transmissions = new List<TransmissionEntity>();
    }

    public MyTaskEntity(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

 

与ASP.NET 6启动时自动创建MongoDB索引相似的内容:

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

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

【源码解读】asp.net core源码启动流程精细解读

引言 core出来至今,已经7年了,我接触也已经4年了,从开始的2.1,2.2,3.1,5,6再到如今的7,一直都有再用,虽然我是一个Winform仔,但是源码一直从3.1到7都有再看,然后在QQ上面也一直比较活跃,之前好几年前一直说给大家解读asp.net core源码,在之前的博客中,讲的都是比

DoNet Core的启动过程-WebApplicationBuilder

1.前言 在NET6开始做ASP.NETCore的开发,我们首先要看的是启动过程,而WebApplication和WebApplicationBuilder 类是启动过程好不开的类,WebApplicationBuilder 来引导启动,这和前面Core的版本引导启动分为Program和Startu

ASP.NET Core设置URLs的几种方法,完美解决.NET 6项目局域网IP地址远程无法访问的问题

近期在dotnet项目中遇到这样的问题:.net6 运行以后无法通过局域网IP地址远程访问。后查阅官方文档。整理出解决问题的五种方式方法,通过新建一个新的WebApi项目演示如下: 说明 操作系统:Ubuntu 22.04.2 运行时:.NET 6 开发工具:Visual Studio 2202 新

开发日志:Kylin麒麟操作系统部署ASP.NET CORE

需求场景: 我需要部署的项目是在Windows上开发的,目标框架为.net core 6.0 因此我们需要先在kylin上部署项目运行所需要的环境。 借助百度词条,先看看Kylin是什么: 服务器资源: 查看系统版本 cat /etc/kylin-release cat /proc/version

.NET 8 Preview 6发布,支持新的了Blazor呈现方案 和 VS Code .NET MAUI 扩展

2023年7月11日 .NET 8 Preview 6,.NET 团队在官方博客发布了系列文章:Announcing .NET 8 Preview 6[1]ASP.NET Core updates in .NET 8 Preview 6[2]Announcing .NET MAUI in .NET

.NET 9 预览版6发布

微软发布了 .NET 9 的第 6 个预览版,此版本包括对运行时、SDK、.NET MAUI、ASP.NET Core 和 C# 的更新,预览版没有包含太多新的主要功能或特性,因为已接近 .NET 9 开发的最后阶段,该开发计划于 11 月全面发布。Loongarch的Native-AOT代码合进去

.NET 8 Preview 5发布,了解一下Webcil 是啥

2023年6月13日 .NET 8 Preview 5,.NET 团队在官方博客发布了系列文章: Announcing .NET 8 Preview 5 ASP.NET Core updates in .NET 8 Preview 5 Announcing .NET MAUI in .NET 8 P

如何将 Autofac 整合进 Net6.0 Core MVC 项目中

一、前言 1、简而言之 Asp.Net Core Mvc,我也用了很长一段时间了,它现在的编程模型和方式还是特别棒的,都是组件开发,什么都可以替换,当然了,您别抬杠,有些还是不能替换的。自从我们进入了跨平台开发的时代,IOC容器也成了一个不可或缺的东西了。微软为我们提供了一个默认实现,那就是 ISe

Asp-Net-Core开发笔记:使用原生的接口限流功能

前言 之前介绍过使用 AspNetCoreRateLimit 组件来实现接口限流 从 .Net7 开始,AspNetCore 开始内置限流组件,当时我们的项目还在 .Net6 所以只能用第三方的 现在都升级到 .Net8 了,当然是得来试试这个原生组件 体验后:配置使用都比较简单,不过功能也没有 A