Track real first attempt question stats
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
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 RecordFirstAttemptAsync(string questionExternalId, string userId, string choiceId, bool isCorrect)
|
||||
{
|
||||
var attempt = new QuestionAttempt
|
||||
{
|
||||
QuestionExternalId = questionExternalId,
|
||||
UserId = userId,
|
||||
ChoiceId = choiceId,
|
||||
IsCorrect = isCorrect,
|
||||
CreatedUtc = DateTime.UtcNow
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await _col.InsertOneAsync(attempt);
|
||||
}
|
||||
catch (MongoWriteException ex) when (ex.WriteError.Category == ServerErrorCategory.DuplicateKey)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
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)).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;
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,9 @@ public class QuestionStore
|
||||
public async Task<Question?> GetByIdAsync(string id) =>
|
||||
await _col.Find(q => q.Id == id).FirstOrDefaultAsync();
|
||||
|
||||
public async Task<Question?> GetByExternalIdAsync(string externalId) =>
|
||||
await _col.Find(q => q.ExternalId == externalId).FirstOrDefaultAsync();
|
||||
|
||||
public async Task<Question?> CreateAsync(UpsertQuestionRequest req)
|
||||
{
|
||||
var question = FromRequest(req);
|
||||
|
||||
Reference in New Issue
Block a user