update pagination
This commit is contained in:
@@ -19,10 +19,50 @@ public class BacktestRepository : IBacktestRepository
|
||||
}
|
||||
|
||||
// User-specific operations
|
||||
public void InsertBacktestForUser(User user, Backtest backtest)
|
||||
public void InsertBacktestForUser(User user, Backtest result)
|
||||
{
|
||||
backtest.User = user;
|
||||
_backtestRepository.InsertOne(MongoMappers.Map(backtest));
|
||||
ValidateBacktestData(result);
|
||||
result.User = user;
|
||||
var dto = MongoMappers.Map(result);
|
||||
_backtestRepository.InsertOne(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that all numeric fields in the backtest are of the correct type
|
||||
/// </summary>
|
||||
private void ValidateBacktestData(Backtest backtest)
|
||||
{
|
||||
// Ensure FinalPnl is a valid decimal
|
||||
if (backtest.FinalPnl.GetType() != typeof(decimal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"FinalPnl must be of type decimal, but got {backtest.FinalPnl.GetType().Name}");
|
||||
}
|
||||
|
||||
// Ensure other numeric fields are correct
|
||||
if (backtest.GrowthPercentage.GetType() != typeof(decimal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"GrowthPercentage must be of type decimal, but got {backtest.GrowthPercentage.GetType().Name}");
|
||||
}
|
||||
|
||||
if (backtest.HodlPercentage.GetType() != typeof(decimal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"HodlPercentage must be of type decimal, but got {backtest.HodlPercentage.GetType().Name}");
|
||||
}
|
||||
|
||||
if (backtest.Score.GetType() != typeof(double))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Score must be of type double, but got {backtest.Score.GetType().Name}");
|
||||
}
|
||||
|
||||
if (backtest.WinRate.GetType() != typeof(int))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"WinRate must be of type int, but got {backtest.WinRate.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Backtest> GetBacktestsByUser(User user)
|
||||
@@ -43,7 +83,8 @@ public class BacktestRepository : IBacktestRepository
|
||||
return backtests.Select(b => MongoMappers.Map(b));
|
||||
}
|
||||
|
||||
public (IEnumerable<Backtest> Backtests, int TotalCount) GetBacktestsByRequestIdPaginated(string requestId, int page, int pageSize)
|
||||
public (IEnumerable<Backtest> Backtests, int TotalCount) GetBacktestsByRequestIdPaginated(string requestId,
|
||||
int page, int pageSize, string sortBy = "score", string sortOrder = "desc")
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var collection = _backtestRepository.GetCollection(); // You may need to expose this in your repo
|
||||
@@ -69,19 +110,44 @@ public class BacktestRepository : IBacktestRepository
|
||||
.Include(b => b.Metadata)
|
||||
.Include(b => b.Config);
|
||||
|
||||
// Build sort definition
|
||||
var sortDefinition = sortBy.ToLower() switch
|
||||
{
|
||||
"score" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.Score)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.Score),
|
||||
"finalpnl" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.FinalPnl)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.FinalPnl),
|
||||
"winrate" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.WinRate)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.WinRate),
|
||||
"growthpercentage" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.GrowthPercentage)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.GrowthPercentage),
|
||||
"hodlpercentage" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.HodlPercentage)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.HodlPercentage),
|
||||
_ => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.Score)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.Score)
|
||||
};
|
||||
|
||||
var afterProjectionMs = stopwatch.ElapsedMilliseconds;
|
||||
var backtests = collection
|
||||
.Find(filter)
|
||||
.Project<BacktestDto>(projection)
|
||||
.Sort(sortDefinition)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Limit(pageSize)
|
||||
.ToList();
|
||||
var afterToListMs = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
Console.WriteLine($"[BacktestRepo] Query: {afterQueryMs}ms, Count: {afterCountMs - afterQueryMs}ms, Projection: {afterProjectionMs - afterCountMs}ms, ToList: {afterToListMs - afterProjectionMs}ms, Total: {afterToListMs}ms");
|
||||
Console.WriteLine(
|
||||
$"[BacktestRepo] Query: {afterQueryMs}ms, Count: {afterCountMs - afterQueryMs}ms, Projection: {afterProjectionMs - afterCountMs}ms, ToList: {afterToListMs - afterProjectionMs}ms, Total: {afterToListMs}ms");
|
||||
|
||||
var mappedBacktests = backtests.Select(b => MongoMappers.Map(b));
|
||||
|
||||
|
||||
return (mappedBacktests, (int)totalCount);
|
||||
}
|
||||
|
||||
@@ -131,4 +197,72 @@ public class BacktestRepository : IBacktestRepository
|
||||
_backtestRepository.DeleteById(backtest.Id.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public (IEnumerable<Backtest> Backtests, int TotalCount) GetBacktestsByUserPaginated(User user, int page,
|
||||
int pageSize, string sortBy = "score", string sortOrder = "desc")
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var collection = _backtestRepository.GetCollection();
|
||||
|
||||
var filter = Builders<BacktestDto>.Filter.Eq(b => b.User.Name, user.Name);
|
||||
|
||||
var afterQueryMs = stopwatch.ElapsedMilliseconds;
|
||||
var totalCount = collection.CountDocuments(filter);
|
||||
var afterCountMs = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
var projection = Builders<BacktestDto>.Projection
|
||||
.Include(b => b.Identifier)
|
||||
.Include(b => b.FinalPnl)
|
||||
.Include(b => b.WinRate)
|
||||
.Include(b => b.GrowthPercentage)
|
||||
.Include(b => b.HodlPercentage)
|
||||
.Include(b => b.User)
|
||||
.Include(b => b.Statistics)
|
||||
.Include(b => b.StartDate)
|
||||
.Include(b => b.EndDate)
|
||||
.Include(b => b.Score)
|
||||
.Include(b => b.RequestId)
|
||||
.Include(b => b.Metadata)
|
||||
.Include(b => b.Config);
|
||||
|
||||
// Build sort definition
|
||||
var sortDefinition = sortBy.ToLower() switch
|
||||
{
|
||||
"score" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.Score)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.Score),
|
||||
"finalpnl" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.FinalPnl)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.FinalPnl),
|
||||
"winrate" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.WinRate)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.WinRate),
|
||||
"growthpercentage" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.GrowthPercentage)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.GrowthPercentage),
|
||||
"hodlpercentage" => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.HodlPercentage)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.HodlPercentage),
|
||||
_ => sortOrder == "desc"
|
||||
? Builders<BacktestDto>.Sort.Descending(b => b.Score)
|
||||
: Builders<BacktestDto>.Sort.Ascending(b => b.Score)
|
||||
};
|
||||
|
||||
var afterProjectionMs = stopwatch.ElapsedMilliseconds;
|
||||
var backtests = collection
|
||||
.Find(filter)
|
||||
.Project<BacktestDto>(projection)
|
||||
.Sort(sortDefinition)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Limit(pageSize)
|
||||
.ToList();
|
||||
var afterToListMs = stopwatch.ElapsedMilliseconds;
|
||||
|
||||
Console.WriteLine(
|
||||
$"[BacktestRepo] User Query: {afterQueryMs}ms, Count: {afterCountMs - afterQueryMs}ms, Projection: {afterProjectionMs - afterCountMs}ms, ToList: {afterToListMs - afterProjectionMs}ms, Total: {afterToListMs}ms");
|
||||
|
||||
var mappedBacktests = backtests.Select(b => MongoMappers.Map(b));
|
||||
|
||||
return (mappedBacktests, (int)totalCount);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ namespace Managing.Infrastructure.Databases.MongoDb.Collections
|
||||
public class BacktestDto : Document
|
||||
{
|
||||
public decimal FinalPnl { get; set; }
|
||||
|
||||
public int WinRate { get; set; }
|
||||
public decimal GrowthPercentage { get; set; }
|
||||
public decimal HodlPercentage { get; set; }
|
||||
|
||||
117
src/Managing.Infrastructure.Database/MongoDb/IndexService.cs
Normal file
117
src/Managing.Infrastructure.Database/MongoDb/IndexService.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using Managing.Infrastructure.Databases.MongoDb.Collections;
|
||||
using Managing.Infrastructure.Databases.MongoDb.Configurations;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Managing.Infrastructure.Databases.MongoDb;
|
||||
|
||||
/// <summary>
|
||||
/// Service responsible for creating and managing MongoDB indexes
|
||||
/// </summary>
|
||||
public class IndexService
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
private readonly ILogger<IndexService> _logger;
|
||||
|
||||
public IndexService(
|
||||
IOptions<ManagingDatabaseSettings> databaseSettings,
|
||||
ILogger<IndexService> logger)
|
||||
{
|
||||
var settings = databaseSettings.Value;
|
||||
var client = new MongoClient(settings.ConnectionString);
|
||||
_database = client.GetDatabase(settings.DatabaseName);
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates all necessary indexes for the application
|
||||
/// </summary>
|
||||
public async Task CreateIndexesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Creating MongoDB indexes...");
|
||||
|
||||
// Create indexes for BacktestDto
|
||||
await CreateBacktestIndexesAsync();
|
||||
|
||||
// Create indexes for GeneticRequestDto
|
||||
await CreateGeneticRequestIndexesAsync();
|
||||
|
||||
_logger.LogInformation("MongoDB indexes created successfully");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to create MongoDB indexes");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates indexes for the BacktestDto collection
|
||||
/// </summary>
|
||||
private async Task CreateBacktestIndexesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var collection = _database.GetCollection<BacktestDto>("Backtests");
|
||||
|
||||
// Create index on RequestId for faster queries
|
||||
var requestIdIndexKeys = Builders<BacktestDto>.IndexKeys.Ascending(b => b.RequestId);
|
||||
var requestIdIndexOptions = new CreateIndexOptions { Name = "RequestId_Index" };
|
||||
var requestIdIndexModel = new CreateIndexModel<BacktestDto>(requestIdIndexKeys, requestIdIndexOptions);
|
||||
|
||||
// Create index (MongoDB will ignore if it already exists)
|
||||
await collection.Indexes.CreateOneAsync(requestIdIndexModel);
|
||||
|
||||
_logger.LogInformation("Backtest RequestId index created successfully");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to create Backtest indexes");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates indexes for the GeneticRequestDto collection
|
||||
/// </summary>
|
||||
private async Task CreateGeneticRequestIndexesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var collection = _database.GetCollection<GeneticRequestDto>("GeneticRequests");
|
||||
|
||||
// Create index on RequestId for faster queries
|
||||
var requestIdIndexKeys = Builders<GeneticRequestDto>.IndexKeys.Ascending(gr => gr.RequestId);
|
||||
var requestIdIndexOptions = new CreateIndexOptions { Name = "RequestId_Index" };
|
||||
var requestIdIndexModel = new CreateIndexModel<GeneticRequestDto>(requestIdIndexKeys, requestIdIndexOptions);
|
||||
|
||||
// Create index on User.Name for user-specific queries
|
||||
var userIndexKeys = Builders<GeneticRequestDto>.IndexKeys.Ascending("User.Name");
|
||||
var userIndexOptions = new CreateIndexOptions { Name = "User_Name_Index" };
|
||||
var userIndexModel = new CreateIndexModel<GeneticRequestDto>(userIndexKeys, userIndexOptions);
|
||||
|
||||
// Create index on Status for filtering by status
|
||||
var statusIndexKeys = Builders<GeneticRequestDto>.IndexKeys.Ascending(gr => gr.Status);
|
||||
var statusIndexOptions = new CreateIndexOptions { Name = "Status_Index" };
|
||||
var statusIndexModel = new CreateIndexModel<GeneticRequestDto>(statusIndexKeys, statusIndexOptions);
|
||||
|
||||
// Create indexes (MongoDB will ignore if they already exist)
|
||||
await collection.Indexes.CreateManyAsync(new[]
|
||||
{
|
||||
requestIdIndexModel,
|
||||
userIndexModel,
|
||||
statusIndexModel
|
||||
});
|
||||
|
||||
_logger.LogInformation("GeneticRequest indexes created successfully");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to create GeneticRequest indexes");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user