通过相关的多对多关联计数获取记录顺序

时间:2015-01-20 15:36:18

标签: ruby-on-rails postgresql join activerecord related-content

Scnerio:

https://www.funtraker.com正在列出电影,电视节目和游戏。在每个资源(电影,电视节目等)的显示页面上,我们要列出相关资源。

架构:

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

现在我想获得一个基于匹配类型的相关电影列表(如果两个电影都有&#39;喜剧类型,则相关两部电影)。这些相关电影需要按最大匹配类型排序。

这里是样本电影和预期输出。

#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] 

希望问题有意义。

更新:寻找仅限SQL的解决方案。我不需要将结果缓存到任何其他表中。

2 个答案:

答案 0 :(得分:3)

您需要在加入后按电影ID的组计数排序 resource_genres,看看下面的纯SQL方法:

方法#1(单一查询)

双重加入resource_genres表格以维护自我类型ID:

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

方法#2(2个查询)

从单独的查询中获取自genre_ids的{​​{1}}。

resource_genres

答案 1 :(得分:0)

如果您在rails代码中找到解决方案,那么它可能会解决您的问题。

def related_movies
  scores_hash = {}
  Movie.joins(:resource_genres).where('resource_genres.genre_id' => resource_genres.pluck(&:genre_id)).where.not(id: self.id).distinct.find_each do |movie|
    scores_hash[movie] = (movie.resource_genres.pluck(:genre_id) & self.resource_genres.pluck(:genre_id)).count
  end
  Hash[scores_hash.sort_by { |movie, score| -score }].keys
end