【问题标题】:How to Rank in Rails After Grouping分组后如何在 Rails 中排名
【发布时间】:2020-07-11 02:27:29
【问题描述】:

在我使用 Postgres 的 Rails 6 应用程序中,我有一个名为 UserCategories 的表。

| id | user_id | category_id | points| rank |

我想做的是:

  1. 按 category_id 对记录进行分组
  2. 按点 (desc) 对每个 category_id 的记录进行排序
  3. 根据 category_id 的记录顺序更新排名字段

示例(所需排名由每个 category_id 的点数确定):

| id | user_id | category_id | points| rank |
| 1  |    1    |    1        |   2   |     |  #  I want rank to be 1
| 2  |    2    |    1        |   1   |     |  #  I want rank to be 2
| 3  |    1    |    2        |   3   |     |  #  I want rank to be 1
| 4  |    2    |    2        |   3   |     |  #  I want rank to be 1

我的模型方法:

  def self.calculate_user_category_ranks
    @user_categories = UserCategory.select(:id, :points, :user_id, :category_id, :rank).all.order(points: :desc).group_by(&:category_id)
    # returns: 
    #   {2=>[#<UserCategory:0x000000000de8be00 id: 2, user_id: 1, category_id: 2, points: 3, rank: 0>, #<UserLeague:0x000000000de8bce8 id: 4, user_id: 2, category_id: 2, points: 3, rank: 0>],
         1=>[#<UserCategory:0x000000000de8bbf8 id: 1, user_id: 1, category_id: 1, points: 2, rank: 0>, <UserLeague:0x000000000de8bb30 id: 3, user_id: 2, category_id: 1, points: 1, rank: 0>]}

    rank = 0
    points_counter = 0

    @user_categories.each do |id, points|
      uc = UserCategory.find(id)
      
      if points != point_counter
        rank += 1
        point_counter = points
      end

      uc.rank = rank
      uc.save
    end
  end

我执行这段代码后:

| id | user_id | category_id | points| rank |
| 1  |    1    |    1        |   2   |  2  |  #  I want rank to be 1
| 2  |    2    |    1        |   1   |  0  |  #  I want rank to be 2
| 3  |    1    |    2        |   3   |  1  |  #  I want rank to be 1
| 4  |    2    |    2        |   3   |  0  |  #  I want rank to be 1

有人可以帮我确定我做错了什么吗?

【问题讨论】:

标签: ruby-on-rails ruby postgresql


【解决方案1】:

出于效率原因,您可能选择将rank 作为数据库列,但数据库规范化的原则表明,拥有一个可以从桌子。因此,认识到出于效率原因您可能不接受此解决方案,让我建议,对于 UserCategory 的任何特定实例,您可以确定其在 Ruby 中的排名:

class UserCategory < ApplicationRecord
  scope :in_the_same_category, ->(category_id) { where("category_id = ?", category_id }

  def in_my_category
    UserCategory.in_the_same_category(category_id)
  end

  def rank
    in_my_category.
      sort_by(&:points).
      reverse.
      map(&:points).
      uniq.
      index(points) + 1
  end
end

【讨论】:

    【解决方案2】:

    开始

    UserCategory.group(:category_id)
    

    然后构建它

    如果确实需要限制返回的字段或者添加where子句那么

    UserCategory.where(some_field: "some_value").select(:id, :points, :user_id, :category_id, :rank).group(:category_id).order(:points :desc)
    

    https://apidock.com/rails/ActiveRecord/QueryMethods/group 了解更多信息

    【讨论】:

      猜你喜欢
      • 2010-10-06
      • 1970-01-01
      • 2020-09-29
      • 1970-01-01
      • 2019-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多