【问题标题】:How to get most clicked records and at-least one child levels resource will be include将包括如何获取最多点击记录和至少一个子级别资源
【发布时间】:2016-06-13 08:46:47
【问题描述】:

我有这样的具有多态关系的模型

class Level1
 has_and_belongs_to_many :level2s
 has_many :resources ,:as => :mediable
end

class Level2
    has_and_belongs_to_many :level1s
    has_many :level3s
    has_many :resources ,:as => :mediable
end

class Level3
    belongs_to :level2
    has_many :resources ,:as => :mediable
end

class Resource
    belongs_to :mediable , polymorphic: true
    has_many :resources ,:as => :mediable
    has_many :clicks ,:as => :mediable
end

class click
    belongs_to :clickable , polymorphic: true
end

当用户在 level1/level2/level3(图像或媒体)中添加资源时,我将这些媒体显示在用户可以点击的地方,每次点击我都会在点击表中保存一个条目

现在我需要当用户在 level1 的显示页面上时,我需要根据点击次数显示 level1s 和 level2s 组合的前 50 个资源,并且将从数据库中获取至少一个资源

我会这样尝试:

Resource.select("resources.*, count(clicks.id) as click_counts")
            .joins( "INNER JOIN clicks ON clicks.clickable_id = resources.id AND clicks.clickable_type='Resource'" )
            .where("(resources.mediable_id IN(1) AND resources.mediable_type='Level1') OR (resources.mediable_id IN(1, 2, 3, 4, 5) AND resources.mediable_type='Level2')")
            .group("resources.id")
            .order("click_counts").limit(50)

它将返回与级别 1 及其相关级别 2 相关的前 50 个资源,但不保证我至少有一个与级别 2 相关的资源。

你能帮我怎么做吗

有可能从未点击过资源,但我必须获得该资源,并且每个级别至少需要一个资源 所以我认为内连接应该改为左外连接

【问题讨论】:

    标签: mysql ruby-on-rails-4 activerecord polymorphic-associations


    【解决方案1】:

    如果你做一些额外的计算对你来说不是问题,你可以通过以下方式轻松实现:

    resources = Resource.select("resources.*, count(clicks.id) as click_counts")
                .joins( "INNER JOIN clicks ON clicks.clickable_id = resources.id AND clicks.clickable_type='Resource'" )
                .where("(resources.mediable_id IN(1) AND resources.mediable_type='Level1') OR (resources.mediable_id IN(1, 2, 3, 4, 5) AND resources.mediable_type='Level2')")
                .group("resources.id")
                .order("click_counts").limit(50)
    
    unless resources.pluck(:mediable_type).include? 'Level2'
    
      resources = resources.limit(49) + Resource.select("resources.*, count(clicks.id) as click_counts")
                .joins( "INNER JOIN clicks ON clicks.clickable_id = resources.id AND clicks.clickable_type='Resource'" )
                .where("resources.mediable_id IN(1, 2, 3, 4, 5) AND resources.mediable_type='Level2'")
                .group("resources.id")
                .order("click_counts").limit(1)
    end
    

    否则,您可以尝试这样的方法(未测试):

    sub_select = "(
       SELECT resources.*, count(clicks.id) as click_counts, 1 as SortKey
       FROM resources 
       INNER JOIN clicks ON clicks.clickable_id = resources.id AND clicks.clickable_type='Resource'
       WHERE resources.mediable_id IN(1, 2, 3, 4, 5) AND resources.mediable_type='Level2'
       GROUP BY resources.id
       ORDER BY mediable_type, click_counts 
       LIMIT 1
    
       UNION ALL
    
       SELECT resources.*, count(clicks.id) as click_counts, 2 as SortKey
       FROM resources 
       INNER JOIN clicks ON clicks.clickable_id = resources.id AND clicks.clickable_type='Resource'
       WHERE (resources.mediable_id IN(1) AND resources.mediable_type='Level1') OR (resources.mediable_id IN(1, 2, 3, 4, 5) AND resources.mediable_type='Level2')
       GROUP BY resources.id
       ORDER BY SortKey, mediable_type, click_counts) as t"
    
    select_sql = "SELECT DISTINCT resources.*, click_counts FROM #{sub_select} LIMIT 50"
    
    results = ActiveRecord::Base.connection.select_all(select_sql).rows # array
    results_ordered = results.sort { |a, b| a.last <=> b.last } # sort by clicks_count
    

    注意事项:

    • SortKey 额外属性保证查询顺序
    • UNION ALL 不会消除任何重复记录。所以我们需要在resources.*, click_counts 列上添加DISTINCT 以删除可能的重复记录('Level2' 的第一个)

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-26
      • 2019-01-16
      • 2014-02-11
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多