83 lines
2.9 KiB
C#
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;
|
|
}
|
|
}
|