perf(analytics): project minimal columns in GetStats/GetAnalyticsOverview #3
@@ -1750,8 +1750,13 @@ Canonical profile:
|
|||||||
{
|
{
|
||||||
var now = DateTime.Now;
|
var now = DateTime.Now;
|
||||||
|
|
||||||
|
// Project to only the columns the stats need instead of materialising full
|
||||||
|
// JobApplication rows (which drag large Description/TranslatedDescription/
|
||||||
|
// TailoredCvText/Notes blobs). Aggregation stays in memory over a small
|
||||||
|
// per-tenant set. Mirrors the projection pattern used by GetTagTrends.
|
||||||
var all = await _db.JobApplications
|
var all = await _db.JobApplications
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
|
.Select(j => new { j.IsDeleted, j.Status, j.DateApplied })
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
var active = all.Where(j => !j.IsDeleted).ToList();
|
var active = all.Where(j => !j.IsDeleted).ToList();
|
||||||
@@ -2668,10 +2673,21 @@ Candidate master CV:
|
|||||||
[HttpGet("analytics-overview")]
|
[HttpGet("analytics-overview")]
|
||||||
public async Task<ActionResult<AnalyticsOverviewDto>> GetAnalyticsOverview(CancellationToken cancellationToken)
|
public async Task<ActionResult<AnalyticsOverviewDto>> GetAnalyticsOverview(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
// Project to only the fields the overview needs instead of Include-ing full
|
||||||
|
// Company + JobApplication rows (avoids loading large description/CV blobs).
|
||||||
var activeJobs = await _db.JobApplications
|
var activeJobs = await _db.JobApplications
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(j => j.Company)
|
|
||||||
.Where(j => !j.IsDeleted)
|
.Where(j => !j.IsDeleted)
|
||||||
|
.Select(j => new
|
||||||
|
{
|
||||||
|
j.Status,
|
||||||
|
j.ResponseReceived,
|
||||||
|
j.ResponseDate,
|
||||||
|
j.DateApplied,
|
||||||
|
j.CompanyId,
|
||||||
|
CompanyName = j.Company.Name,
|
||||||
|
CompanySource = j.Company.Source
|
||||||
|
})
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
var funnelMap = new Dictionary<string, int>
|
var funnelMap = new Dictionary<string, int>
|
||||||
@@ -2686,7 +2702,7 @@ Candidate master CV:
|
|||||||
var funnel = funnelMap.Select(x => new FunnelStagePoint(x.Key, x.Value)).ToList();
|
var funnel = funnelMap.Select(x => new FunnelStagePoint(x.Key, x.Value)).ToList();
|
||||||
|
|
||||||
var responseRateBySource = activeJobs
|
var responseRateBySource = activeJobs
|
||||||
.GroupBy(j => string.IsNullOrWhiteSpace(j.Company?.Source) ? "Unknown source" : j.Company!.Source!.Trim())
|
.GroupBy(j => string.IsNullOrWhiteSpace(j.CompanySource) ? "Unknown source" : j.CompanySource!.Trim())
|
||||||
.Select(g => new ResponseRatePoint(
|
.Select(g => new ResponseRatePoint(
|
||||||
g.Key,
|
g.Key,
|
||||||
g.Count(),
|
g.Count(),
|
||||||
@@ -2699,7 +2715,7 @@ Candidate master CV:
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var topCompanies = activeJobs
|
var topCompanies = activeJobs
|
||||||
.GroupBy(j => new { j.CompanyId, Name = j.Company.Name })
|
.GroupBy(j => new { j.CompanyId, Name = j.CompanyName })
|
||||||
.Select(g => new CompanyActivityPoint(
|
.Select(g => new CompanyActivityPoint(
|
||||||
g.Key.CompanyId,
|
g.Key.CompanyId,
|
||||||
g.Key.Name,
|
g.Key.Name,
|
||||||
|
|||||||
Reference in New Issue
Block a user