will_paginate in rails 使用连接和分组时

will_paginate in rails when using join and group by

我注意到当使用 will_paginate 20 个结果页面时,加入多个 tables group_by "nickname",输出是分页的但 3 "nicknames"只显示(这是有道理的,因为分页在分组依据之前计算了输出)但我该如何解决呢?另外,我想像那样显示输出并根据 "nickname" 列限制每页的项目数:请注意 "data" table 有很多 "preferences"。 (data.id = preferences.data_id)

{
"totalCount": 123,
  "pageInfo": {
    "currentPage": 1,
    "nextPage": 2,
    "lastPage": 8
  },
  "results": [
    {
      "data": {
        "id": 1,
        "nickname": "foo"
      },
      "preferences": [
        {
          "id": 4479,
          "created_at": "2019-05-21T00:39:45.772Z",
          "updated_at": "2019-05-21T00:39:45.772Z",
          "title": "Check Database",
          ...
        },
        ...
      ]
    },
    ...
  ]
}

  data_res = Data.paginate(page: params[:page], per_page: 
  20).joins("INNER JOIN preferences ON data.id = 
  preferences.data_id").select("data.*, preferences.*").order(id: :asc)
  data_group_by = data_res.group_by { |r| r.nickname }
  respond_to do |format|
        format.any
        format.json {
          render :json => {
              :totalCount => data_res.total_entries,
              :pageInfo => {
                  :currentPage => data_res.current_page,
                  :nextPage => data_res.next_page,
                  :total_pages => data_res.total_pages,
                  :per_page => data_res.per_page,
              },
              :results =>  data_res
          }
        }
      end

如果我对你的问题的理解正确(可能不正确),分页显示它有 20 条记录,但你只看到返回 3 条记录,因为它们被分组了?

但是,您想要的是 20 条记录,并分组了 20x 个首选项?

如果是这样,我认为您的查询可能过于复杂了。

  1. 我认为你不应该使用 select("data.*, preferences.*") 因为它基本上只是为每个获取的首选项添加一条新记录,所以首选项可能是你获得多少记录的决定因素而不是 data 您正在对其进行分页 + 您正在为返回的每个数据动态添加其他方法以说明首选项
  2. data_res.group_by { |r| r.nickname } 似乎没有必要,除非您的数据记录不是唯一的,在这种情况下,我会质疑按此对它们进行分组的原因。

在我看来,如果昵称是唯一的,即只能有 1 个 data 记录具有相同的 nickname,这就是我的建议

class Data
   has_many :preferences
end
class Preference
   belongs_to :data
end

joins-ing and includes-ing here to ensure the preferences are eager loaded, while conforming to your existing query of only fetching data with preferences

data_res = Data.joins(:preference).includes(:preference).paginate(page: params[:page], per_page: 20).order(id: :asc) # this should give you 20 records of data that has preferences

然后你的序列化程序可以完成剩下的工作以确保你的数据被正确映射并且你的偏好处于同一级别(有几种方法可以通过任何序列化包实现),例如

class DataPreferencesSerializer < AMS
  attributes :data
             :preferences # or can be has_many :preferences serializer
  def data
   {id: object.id, nickname: object.nickname }
  end

  def preferences
   object.preferences
  end
end

results= ArraySerializer.new(data_res, each_serializer: DataPreferencesSerializer, root: false)

正如我所说,有多种实现序列化的方法,因此上面的实现只是您可能采用的方法的想法,而不是具体的实现。

PS:您的 INNER JOIN 确保所有返回的 data 记录都有关联的 preferences,因此任何 data 没有至少一个 preference 可能已从您返回的记录中排除。