https://www.funtraker.com is listing movies, tv shows and games. On show page of each resource(Movie, Tv Show etc) we want to list down the related resources.
class Movie < AR::Base
has_many :resource_genres, as: :resource
has_many :genres, through: :resource_genres
end
class ResourceGenre
belongs_to :resource, polymorphic: true
end
Now I want to get a list of related movies based on matched genre( two movies are related if both has 'comedy` genre). And these related movies need to order by max number of matched genres.
Well here is sample movies and the expected output.
#Input
Movie Genres
Movie 1: horror, comedy, action, war
Movie 2: action, thriller, crime, animation
Movie 3: comedy, war, action, thriller
Movie 4: crime, animation, action, war
#Expected output
movie1.related_movies => [ movie3, movie2 ]
movie4.related_movies => [ movie2, remaining-three-movies-in-any-order ]
movie3.related_movies => [ movie1, movie2, movie4]
Hopefully question make sense.
UPDATE: Looking for SQL only solution. I don't need to cache the results in any another table.
You need to order by the group count of the movies ids after joined with
resource_genres
, take a look at the following pure SQL methods:
Double joining the resource_genres
table on itself to maintain self genres ids:
def related_movies
Movie.select("movies.*, COUNT(*) AS group_count").
joins(:resource_genres).
joins("JOIN resource_genres rg ON rg.genre_id = resource_genres.genre_id").
where("rg.resource_type = 'Movie'
AND rg.resource_id = ?
AND movies.id != ?", self.id, self.id).
group('movies.id').
order('group_count DESC')
end
Plucking the genre_ids
from self resource_genres
on a separate query.
def related_movies
Movie.select("movies.*, COUNT(*) AS group_count").joins(:resource_genres).
where("resource_genres.genre_id IN (?)
AND movies.id != ?", self.resource_genres.pluck(:genre_id), self.id).
group('movies.id').
order('group_count DESC')
end