گاهی اوقات نیازمند آن هستنید که دیتاهایی را برای مدت زمان مشخصی نگه دارید و سپس آنها را پاک کنید. اگر بخواهید خودتان این کار را انجام دهید، کاری وقت گیر و غیرمعقولی را انجام می‌دهید. اما می‌توانید با استفاده از Expiration time مربوط به دیتابیس Mongo و یا TTL مربوط به ردیس این کار را انجام دهید. در این مطلب می‌خواهیم یک ایندکس در دیتابیس Mongo ایجاد کنیم که مشخص شود دیتاهای وارد شده بعد از چه مدت زمانی به صورت خودکار پاک شوند.
برای اینکار ابتدا یک پروژه از نوع Asp.Net Core WebApplication ایجاد میکنیم. سپس باید یک Repository برای خواندن و نوشتن دیتاها در Mongo ایجاد کنیم. برای کار با دیتابیس MongoDb باید پکیج MongoDB.Driver را نصب نمایید.
ریپازتوری مربوط به User:

public class UserMongoDbRepository : IUserRepository
{
    private readonly IMongoCollection<User> _userCollection;
    private readonly ILogger<UserMongoDbRepository> _logger;

    public UserMongoDbRepository(ILogger<UserMongoDbRepository> logger, IOptions<MongoDbConfiguration> options)
    {
        _logger = logger; 
        var mongoClient = new MongoClient(options.Value.ConnectionString);
        var database = mongoClient.GetDatabase(options.Value.DatabaseName);
        _userCollection = database.GetCollection<User>(options.Value.CollectionName);
    }
 
    public async Task AddUser(User user, CancellationToken cancellationToken)
    {
        await _userCollection.InsertOneAsync(user, null, cancellationToken);
    }
    public async Task<User> GetUserById(int id, CancellationToken cancellationToken)
    {
        var filter = Builders<User>.Filter.Eq(a => a.Id, id);

        var result = await _userCollection.FindAsync(filter, cancellationToken: cancellationToken);

        return await result.FirstOrDefaultAsync(cancellationToken);
    }
}

ریپازیتوری پیاده سازی شده شامل دو متد اضافه کردن و خواندن می‌باشد. اما اگر بخواهیم دیتاهای بعد از یک مدت زمان مشخصی به صورت خودکار پاک شوند باید تنظیمات مربوط به ایندکس را به MongoDb اضافه کنیم. برای اینکار یک به نام CreateExpireIndex ایجاد می‌کنیم که تنظیمات مربوط به ایندکس را ایجاد کند.

private void CreateExpireIndex(MongoDbConfiguration mongoDbConfiguration)
{
    var isValidExpireFormat = TimeSpan.TryParseExact(mongoDbConfiguration.ExpireAfter,
        mongoDbConfiguration.ExpireFormat,
        CultureInfo.InvariantCulture,
        out TimeSpan expireAfter);

    if (isValidExpireFormat)
    {
        const string _expireAt = "ExpireAt";
        var expireIndex = new IndexKeysDefinitionBuilder<User>().Ascending(c => c.CreationTime);

        var index = _userCollection.Indexes.List().ToList()
            .Where(a => a["name"] == _expireAt)
            .Select(a => new
            {
                ExpireAfterSeconds = a.GetElement("expireAfterSeconds").Value.ToString()
            }).FirstOrDefault();

        if (index != null)
        {
            var registeredExpireAfter = TimeSpan.FromSeconds(Convert.ToInt64(index.ExpireAfterSeconds));
            if (registeredExpireAfter == expireAfter)
            {
                return;
            }
            _userCollection.Indexes.DropOne(_expireAt);
            _logger.LogInformation($"Index deleted. {registeredExpireAfter.ToString(mongoDbConfiguration.ExpireFormat)}");
        }

        _userCollection.Indexes.CreateOne(new CreateIndexModel<User>(expireIndex, new CreateIndexOptions
        {
            Name = _expireAt,
            ExpireAfter = expireAfter
        }));
        _logger.LogInformation($"Index created. {expireAfter.ToString(mongoDbConfiguration.ExpireFormat)}");
    }
}

مدت زمان مشخص شده برای پاک کردن را از appsettings.json میخوانیم و از آن یک TimeSpan ایجاد می‌کنیم. سپس در صورتی که دیتای وارد شده در appsettings.json معتبر باشد، ادامه‌ی کار اضافه کردن ایندکس انجام می‌شود. در صورتی که از قبل ایندکس مورد نظر اضافه شده باشد و مجدد ایندکس را اضافه کنید با خطا مواجه می‌شوید به همین دلیل ابتدا لیست ایندکس‌های ایجاد شده را دریافت می‌کنیم و در صورتی که ایندکس وجود نداشته باشد و یا ایندکس موجود باشد اما مقدار آن با مقدار خوانده شده از appsettigs.json برابر نباشد، ایندکس قبلی پاک می‌شود و ایندکس جدید اضافه خواهد شد اما اگر مقدار ایندکس برابر با مقدار خوانده شده از appsettings.json باشد عملیاتی صورت نخواهد گرفت. سپس این متد را باید در سازنده ریپازیتوری فراخوانی کنیم.

public UserMongoDbRepository(ILogger<UserMongoDbRepository> logger, IOptions<MongoDbConfiguration> options)
{
    _logger = logger; 
    var mongoClient = new MongoClient(options.Value.ConnectionString);
    var database = mongoClient.GetDatabase(options.Value.DatabaseName);
    _userCollection = database.GetCollection<User>(options.Value.CollectionName);
    CreateExpireIndex(options.Value);
}

و در نهایت باید ریپازیتوری ایجاد شده را در سرویس‌ها رجیستر کنیم:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MongoDbConfiguration>(a => Configuration.GetSection(nameof(MongoDbConfiguration)).Bind(a));
    services.AddControllers();
    services.AddSingleton<IUserRepository, UserMongoDbRepository>();
}

مدل مربوط به MongoDbConfiguration:

public class MongoDbConfiguration
{
    public string DatabaseName { get; set; }
    public string ConnectionString { get; set; }
    public string CollectionName { get; set; }
    public string ExpireAfter { get; set; }
    public string ExpireFormat { get; set; }
}

مقدار appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "MongoDbConfiguration": {
    "ConnectionString": "connectionString",
    "DatabaseName": "TestDb",
    "CollectionName": "User",
    "ExpireFormat": "dd':'hh':'mm':'ss",
    "ExpireAfter": "02:00:00:00"
  }
}

در appsettings.json ارسال شده، مدت زمان ثبت شده برابر با 2 روز است. توجه داشته باشید که در صورتی که فرمت وارد شده صحیح نباشد، ایندکس مورد نظر شما ایجاد نمی‌شود ابتدا باید از صحت فرمت (ExpireFormat) و مقدار آن (ExpireAfter) آن اطمینان حاصل کنید و سپس برنامه را اجرا کنید.

;)

Powered by Froala Editor

نظرات