【问题标题】:How to a order a list of records based on how many of their associated records match records in a given array?如何根据给定数组中的关联记录匹配记录的数量对记录列表进行排序?
【发布时间】:2015-04-17 03:05:19
【问题描述】:

对不起,如果标题不清楚,我不知道如何更好地表达它。

我有一个模型“Playlist”,它通过中间模型“PlaylistUser”拥有_many 和属于_另一个模型“User”。

假设我在给定播放列表 (@playlist) 和 @users = @playlist.users 的页面上。如何按与@playlist 共享的用户数量排序所有其他播放列表?

所以如果@playlist.users = ["joe","nick","bob"]<playlist2>.users = ["nick","bob","tom"]<playlist 3>.users = ["bob","jim","rich"],playlist2 应该排在第一位,因为它与@playlist 共享 2 个用户,而 playlist3 仅共享 1 个用户。

我希望我已经把我想做的事情说得够清楚了,但如果需要进一步澄清,请告诉我。

协会:

class Playlist < ActiveRecord::Base
  has_many :playlist_users
  has_many :users, :through => :playlist_users
end

class PlaylistUser < ActiveRecord::Base
  belongs_to :playlist
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :playlist_users
  has_many :playlists, :through => :playlist_users
end

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4


    【解决方案1】:
    Playlist.joins(:users)
      .where.not(id: @playlist.id)
      .where(users: {id: @playlist.user_ids})
      .group(:id)
      .order('count(*) desc')
    

    或者,如果你需要访问count(*)的结果:

    @playlists = Playlist.select('playlists.*, count(*) as shared_users_count')
      .joins(...)
      ...
      .order('shared_users_count desc')
    
    # print out shared users count
    @playlists.each { |pl| puts pl.shared_users_count }
    

    【讨论】:

    • 感谢您的精彩回答!如果我用该代码打印一个块:Playlist.(...).each do |p|,我怎样才能打印出“count(*)”的值? p.count(*) 返回错误。
    【解决方案2】:

    这将稍微简化您的模型。您已经确定了“has and belongs to many”关系,这就是如何实现它。

    首先,您只需要两个模型。播放列表和用户

    class Playlist < ActiveRecord::Base
      has_and_belongs_to_many :users
    end
    
    class User < ActiveRecord::Base
      has_and_belongs_to_many :playlists
    end
    

    接下来你需要 3 张桌子。

    class SampleMigration < ActiveRecord::Migration
      def change
        create_table :users do |t|
          t.string :name
        end
    
        create_table :playlists do |t|
          t.string  :name
        end
    
        create_table :playlists_users, id: false do |t|
          t.belongs_to :playlist
          t.belongs_to :user
        end
      end
    end
    

    请注意,复数在命名集合时很重要,例如 has_and_belongs_to_many :users 和作为表的名称 create_table :users

    连接表不需要模型,但需要按字母顺序命名,并且名称是复数形式。

    现在您可以使用user.playlists 返回连接到该用户的播放列表数组。作为一个数组,您可以调用 user.playlists[5] 来获取列表中的第 5 首歌曲,或者您可以遍历它 user.playlists.each do |list|

    所以如果@playlist.users = ["joe","nick","bob"], .users = ["nick","bob","tom"] 和 .users = ["bob"," jim","rich"], playlist2 应该排在最前面,因为它与@playlist 共享 2 个用户,而 playlist3 只共享 1 个用户。

    有两种方法可以实现这一目标。通过在 Rails 中检索所有列表并将它们合并的帮助方法,或通过 SQL 查询。 SQL 更快,但需要 SQL 知识。最初我会使用 Rails 并在有收获时处理 SQl。

    一个实现可能是(注意:将此视为伪代码,我没有测试过);

    # get all the lists
    newPlaylist = array.new
    users = @playlist.users
    users.each do |user|
       newPlaylist = newPlaylist + user.playlists
    end
    
    # count all the lists
    countPlaylists = Hash.new
    newPlaylist.each do |list| 
       if list.in? countPlaylists.keys
           countPlaylists[list] = countPlaylists[list] + 1
       else
           countPlaylists[list] = 1
       end
    end
    
    # sort the list - I'm not sure if it sorts on keys or values,
    # but either way you should be able to figure it out
    countPlaylists.sort
    

    【讨论】:

      猜你喜欢
      • 2020-04-16
      • 2016-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-13
      • 1970-01-01
      • 2018-03-25
      • 1970-01-01
      相关资源
      最近更新 更多