SUM(ABS(vote))
Eloquent - calculate two field values and order according to result.
I am building a query calling a collection of track to build up a track list. There’s a bunch of relationships that go with this.
- A track has a song (one to one)
- A track has votes (one to many)
- A song has artists (many to many)
I can call all this with
Track::where('tracks.listing_id', $id)
->with('song', 'song.artists', 'votes')
->get();
I want to order the track by the amount of votes they have. Seems fairly simple BUT a vote can be positive (up vote) or negative (down vote). The votes records have a “vote” field in which the value can be “1” or “-1”. This means I can’t just count the number of records in the votes table for one given track.
So, how can I calculate the up and down votes to get an actual votes count and order my query results on that? Is it even possible
I played around with withCount() which allows me to count only the up-votes or down-votes but I could really use some help here. Maybe what I’m after isn’t even possible.
This should do the trick (not had chance to test it!).
Either via a JOIN:
Track::with('song', 'song.artists', 'votes')
->select('tracks.*', DB::raw('SUM(votes.vote) AS vote_count'))
->leftJoin('votes', 'tracks.id', '=', 'votes.track_id')
->where('tracks.listing_id', $id)
->groupBy('tracks.id')
->orderBy('vote_count')
->get();
Or alternatively, via a SUBQUERY:
Track::with('song', 'song.artists', 'votes')
->select('tracks.*', DB::raw('(SELECT SUM(votes.vote) FROM votes WHERE tracks.id = votes.track_id) AS vote_count'))
->where('tracks.listing_id', $id)
->orderBy('vote_count')
->get();
It's worth mentioning, left joins are supposed to be more performant (not sure how much more) but subqueries are arguably more easier to read. Up to you which you choose... as long as it's not the red pill ;)
Please or to participate in this conversation.