Files
step3/api/QuestionsApi/Services/QuestionAttemptStore.cs
T
2026-07-11 02:05:43 -05:00

83 lines
2.9 KiB
C#

using MongoDB.Driver;
using QuestionsApi.Models;
namespace QuestionsApi.Services;
public class QuestionAttemptStore
{
private readonly IMongoCollection<QuestionAttempt> _col;
public QuestionAttemptStore(IConfiguration cfg)
{
var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
var dbName = cfg["MongoDB:DatabaseName"] ?? "GameDb";
var client = new MongoClient(cs);
var db = client.GetDatabase(dbName);
_col = db.GetCollection<QuestionAttempt>("QuestionAttempts");
var firstAttemptIndex = Builders<QuestionAttempt>.IndexKeys
.Ascending(a => a.QuestionExternalId)
.Ascending(a => a.UserId);
_col.Indexes.CreateOne(new CreateIndexModel<QuestionAttempt>(
firstAttemptIndex,
new CreateIndexOptions { Unique = true }));
var questionIndex = Builders<QuestionAttempt>.IndexKeys.Ascending(a => a.QuestionExternalId);
_col.Indexes.CreateOne(new CreateIndexModel<QuestionAttempt>(questionIndex));
}
public async Task<bool> RecordFirstAttemptAsync(string questionExternalId, string userId, string choiceId, bool isCorrect, bool isSkip = false)
{
var attempt = new QuestionAttempt
{
QuestionExternalId = questionExternalId,
UserId = userId,
ChoiceId = choiceId,
IsCorrect = isCorrect,
IsSkip = isSkip,
CreatedUtc = DateTime.UtcNow
};
try
{
await _col.InsertOneAsync(attempt);
return true;
}
catch (MongoWriteException ex) when (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
{
return false;
}
}
public async Task<Dictionary<string, int>> GetPercentagesForQuestionAsync(string questionExternalId)
{
var results = await GetPercentagesByQuestionAsync([questionExternalId]);
return results.GetValueOrDefault(questionExternalId, []);
}
public async Task<Dictionary<string, Dictionary<string, int>>> GetPercentagesByQuestionAsync(IEnumerable<string> questionExternalIds)
{
var ids = questionExternalIds.Where(id => !string.IsNullOrWhiteSpace(id)).Distinct().ToList();
if (ids.Count == 0)
return [];
var attempts = await _col.Find(a => ids.Contains(a.QuestionExternalId) && !a.IsSkip).ToListAsync();
var output = new Dictionary<string, Dictionary<string, int>>();
foreach (var group in attempts.GroupBy(a => a.QuestionExternalId))
{
var total = group.Count();
if (total == 0)
continue;
output[group.Key] = group
.GroupBy(a => a.ChoiceId)
.ToDictionary(
choiceGroup => choiceGroup.Key,
choiceGroup => (int)Math.Round(choiceGroup.Count() * 100.0 / total));
}
return output;
}
}