Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 77 additions & 33 deletions app/Filament/Widgets/JobsByCategoryChart.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,27 @@ protected function getData(): array
'#8b5cf6', '#06b6d4', '#ec4899', '#84cc16',
];

// Generate data for each category over the last 8 weeks
foreach ($topCategories as $index => $category) {
$data = Trend::query(
JobListing::where('job_category', $category->id)
)
->between(
start: now()->subWeek(),
end: now(),
)
->perWeek()
->count();

$datasets[] = [
'label' => $category->name,
'data' => $data->map(fn (TrendValue $value) => $value->aggregate)->toArray(),
'borderColor' => $colors[$index % count($colors)],
'backgroundColor' => $colors[$index % count($colors)].'20',
'tension' => 0.3,
];
}

// Get labels for the last 8 weeks
$labels = Trend::query(JobListing::class)
$startDate = now()->subWeek();
$endDate = now();

// Get all data in a single optimized query to prevent N+1
$jobData = JobListing::selectRaw("
job_category,
date_format(created_at, '%Y-%u') as date_week,
count(*) as count
")
->whereIn('job_category', $topCategories->pluck('id'))
->whereBetween('created_at', [$startDate, $endDate])
->groupBy(['job_category', 'date_week'])
->orderBy('date_week')
->get()
->groupBy('job_category');

// Get labels for the date range
$labels = Trend::query(JobListing::query())
->between(
start: now()->subWeek(),
end: now(),
start: $startDate,
end: $endDate,
)
->perWeek()
->count()
Expand All @@ -70,6 +65,37 @@ protected function getData(): array
}
})->toArray();

// Build data array matching the trend format (moved outside the loop to prevent N+1)
$trendData = Trend::query(JobListing::query())
->between(
start: $startDate,
end: $endDate,
)
->perWeek()
->count();

// Generate datasets for each category using the pre-fetched data
foreach ($topCategories as $index => $category) {
$categoryData = $jobData->get($category->id, collect());

// Create a map of week -> count for this category
$weekCounts = $categoryData->pluck('count', 'date_week');

$data = $trendData->map(function (TrendValue $value) use ($weekCounts) {
$week = \Carbon\Carbon::parse($value->date)->format('Y-W');

return $weekCounts->get($week, 0);
})->toArray();

$datasets[] = [
'label' => $category->name,
'data' => $data,
'borderColor' => $colors[$index % count($colors)],
'backgroundColor' => $colors[$index % count($colors)].'20',
'tension' => 0.3,
];
}
Comment on lines +78 to +97
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The Trend query inside the foreach loop causes an N+1 query problem, as it's executed for every category. This query should be moved outside the loop to be executed only once, improving performance significantly.

            // Build data array matching the trend format
            $trendData = Trend::query(JobListing::query())
                ->between(
                    start: $startDate,
                    end: $endDate,
                )
                ->perWeek()
                ->count();

            // Generate datasets for each category using the pre-fetched data
            foreach ($topCategories as $index => $category) {
                $categoryData = $jobData->get($category->id, collect());

                // Create a map of week -> count for this category
                $weekCounts = $categoryData->pluck('count', 'date_week');

                $data = $trendData->map(function (TrendValue $value) use ($weekCounts) {
                    $week = \Carbon\Carbon::parse($value->date)->format('Y-W');

                    return $weekCounts->get($week, 0);
                })->toArray();

                $datasets[] = [
                    'label' => $category->name,
                    'data' => $data,
                    'borderColor' => $colors[$index % count($colors)],
                    'backgroundColor' => $colors[$index % count($colors)].'20',
                    'tension' => 0.3,
                ];
            }


return [
'datasets' => $datasets,
'labels' => $labels,
Expand All @@ -93,25 +119,43 @@ private function getFallbackData(): array
'#8b5cf6', '#06b6d4', '#ec4899', '#84cc16',
];

// Generate labels for the last 8 weeks
// Generate labels for the last 2 weeks
for ($i = 1; $i >= 0; $i--) {
$startOfWeek = now()->subWeeks($i)->startOfWeek();
$labels[] = $startOfWeek->format('M j');
}

// Generate data for each category
// Get all job data in a single optimized query
$startDate = now()->subWeeks(1)->startOfWeek();
$endDate = now()->endOfWeek();

$jobData = JobListing::selectRaw('
job_category,
WEEK(created_at, 3) as week_num,
YEAR(created_at) as year_num,
count(*) as count
')
->whereIn('job_category', $topCategories->pluck('id'))
->whereBetween('created_at', [$startDate, $endDate])
->groupBy(['job_category', 'week_num', 'year_num'])
->get()
->groupBy('job_category');

// Generate data for each category using pre-fetched data
foreach ($topCategories as $index => $category) {
$categoryData = $jobData->get($category->id, collect());
$data = [];

for ($i = 1; $i >= 0; $i--) {
$startOfWeek = now()->subWeeks($i)->startOfWeek();
$endOfWeek = now()->subWeeks($i)->endOfWeek();
$weekStart = now()->subWeeks($i)->startOfWeek();
$weekNum = $weekStart->week;
$yearNum = $weekStart->year;

$count = JobListing::where('job_category', $category->id)
->whereBetween('created_at', [$startOfWeek, $endOfWeek])
->count();
$weekData = $categoryData->where('week_num', $weekNum)
->where('year_num', $yearNum)
->first();

$data[] = $count;
$data[] = $weekData ? (int) $weekData->count : 0;
}

$datasets[] = [
Expand Down