From a842cb3306a31d2627151753aafa883cc9bced12 Mon Sep 17 00:00:00 2001 From: Ian Littman Date: Wed, 6 Mar 2019 19:05:07 -0600 Subject: [PATCH] Take N^2+1 queries down to N+1 via custom leaderboard query --- app/Challenge.php | 29 +++++++++----------- app/Http/Controllers/ChallengeController.php | 8 ++++-- app/Query/ChallengeStats.php | 19 +++++++++++++ 3 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 app/Query/ChallengeStats.php diff --git a/app/Challenge.php b/app/Challenge.php index b5e5307..88cb3c9 100644 --- a/app/Challenge.php +++ b/app/Challenge.php @@ -2,6 +2,7 @@ namespace Challengr; +use Challengr\Query\ChallengeStats; use Illuminate\Database\Eloquent\Model; /** @@ -62,17 +63,15 @@ public function getLeaderboard() public function getDurationLeaderboard() { - $arr = $this->users_joined->map(function(User $user) { + $stats = ChallengeStats::getForChallenge($this->id); + + $arr = $this->users_joined->map(function(User $user) use ($stats) { return [ 'id' => $user->id, 'name' => $user->name, - 'duration_seconds' => $durationInSeconds = $user->activities() - ->whereBetween('started_at', [$this->starts_at, $this->ends_at]) - ->sum('duration'), - 'distance_miles' => $user->activities() - ->whereBetween('started_at', [$this->starts_at, $this->ends_at]) - ->sum('distance_miles'), - 'duration' => Util::secondsToTime($durationInSeconds), + 'duration_seconds' => $stats[$user->id]['duration'] ?? 0, + 'distance_miles' => $stats[$user->id]['distance_miles'] ?? 0, + 'duration' => Util::secondsToTime($stats[$user->id]['duration'] ?? 0), ]; })->toArray(); usort($arr, function ($a, $b) { @@ -83,17 +82,15 @@ public function getDurationLeaderboard() public function getDistanceLeaderboard() { - $arr = $this->users_joined->map(function(User $user) { + $stats = ChallengeStats::getForChallenge($this->id); + + $arr = $this->users_joined->map(function(User $user) use ($stats) { return [ 'id' => $user->id, 'name' => $user->name, - 'duration_seconds' => $durationInSeconds = $user->activities() - ->whereBetween('started_at', [$this->starts_at, $this->ends_at]) - ->sum('duration'), - 'distance_miles' => $user->activities() - ->whereBetween('started_at', [$this->starts_at, $this->ends_at]) - ->sum('distance_miles'), - 'duration' => Util::secondsToTime($durationInSeconds), + 'duration_seconds' => $stats[$user->id]['duration'] ?? 0, + 'distance_miles' => $stats[$user->id]['distance_miles'] ?? 0, + 'duration' => Util::secondsToTime($stats[$user->id]['duration'] ?? 0), ]; })->toArray(); usort($arr, function ($a, $b) { diff --git a/app/Http/Controllers/ChallengeController.php b/app/Http/Controllers/ChallengeController.php index 6448c60..a1db750 100644 --- a/app/Http/Controllers/ChallengeController.php +++ b/app/Http/Controllers/ChallengeController.php @@ -15,9 +15,11 @@ class ChallengeController extends Controller public function forCurrentUser(Request $request) { return [ - 'created' => Challenge::whereUserId($userId = $request->user()->id)->orderByDesc('created_at')->get(), - 'joined' => Challenge::whereHas('users_joined', function(Builder $builder) use ($userId) { - return $builder->whereKey($userId); + 'created' => Challenge::with('users_joined') + ->whereUserId($userId = $request->user()->id)->orderByDesc('created_at')->get(), + 'joined' => Challenge::with('users_joined') + ->whereHas('users_joined', function(Builder $builder) use ($userId) { + return $builder->whereKey($userId); })->orderByDesc('ends_at')->get() ]; } diff --git a/app/Query/ChallengeStats.php b/app/Query/ChallengeStats.php new file mode 100644 index 0000000..a7225cb --- /dev/null +++ b/app/Query/ChallengeStats.php @@ -0,0 +1,19 @@ +user_id] = ['distance_miles' => $row->distance_miles, 'duration' => $row->duration]; + } + return $ret; + } +}