ruby-on-rails Rails:multi通过一次快速查询找出一个类别是否有成员

w1e3prcc  于 2023-01-27  发布在  Ruby
关注(0)|答案(2)|浏览(157)

给定模型:

  • Member-〉belongs_to :category
  • Category-〉has_many :members

我想知道每个类别是否有成员,其形式如下:

----------------------
| name | has_members |
======================
| cat1 | true        |
| cat2 | false       |
| cat3 | true        |
----------------------

以下解决方案的速度太慢,无法实现这一目标:

  • Category.eager_load(:members).map{|s| s.members.any?}
  • Category.includes(:members).map{|s| s.members.any?}

这将是计数器缓存的一个用例,但我想知道这是否可以通过一些智能ARel或SQL来解决。
实现这一目标的最快方法是什么?

sd2nnvve

sd2nnvve1#

如果你把这个问题逆过来:

Member.includes(:category).order(:category_id).distinct.map{ |m| m.category !=nil ? m.category.name : "" }
mqkwyuun

mqkwyuun2#

此查询应返回值的哈希值,其中包含成员的名称和计数。

Category.includes(:members).distinct.select('categorys.name, COUNT(members.*)').group('category.name').count(:members)
#=> {"cat1"=>1,
 "cat2"=>1,
 "cat3"=>0,
 "cat4"=>2,...}

如果您只想查看成员数大于零的类别,可以执行以下操作:

Category.joins(:members).distinct.select('categorys.name, COUNT(members.*)').group('category.name').count(:members)
#=> {"cat1"=>1,
 "cat2"=>1,
 "cat4"=>2,...}

这将忽略members = 0的类别。
查询本身可能并不是让你慢下来的原因,而是你把它们都传递给.map,这是一个ruby方法,而不是SQL。我认为任何比我给你的更快的东西,你都必须直接进入带有计数器缓存的数据库。同样在纯SQL查询中,你可以添加一个CASE语句来交换数字〉或〈0的true/false。

相关问题