如何用ActiveRecord查询无角色关联的Editor(多对多关系)
查询无角色关联的Editor记录
现有多对多关联模型
class Editor < ApplicationRecord has_many :editor_roles, dependent: :destroy has_many :roles, through: :editor_roles end
class Role < ApplicationRecord has_many :editor_roles, dependent: :destroy has_many :editors, through: :editor_roles end
class EditorRole < ApplicationRecord belongs_to :editor belongs_to :role end
需求
仅列出没有角色(roles_count == 0)的Editor记录。
错误写法分析
你尝试的语句Editor.joins(:roles).group('editors.id').having('count(roles) = 0')无法得到正确结果,因为joins(:roles)是内连接,只会返回存在角色关联的Editor记录,这类记录的角色数量不可能为0。
正确实现方式
方式1:左外连接 + 分组统计
使用left_joins保留所有Editor记录,再通过统计关联角色ID的数量筛选无角色的记录:
Editor.left_joins(:roles) .group('editors.id') .having('COUNT(roles.id) = 0')
注:COUNT(roles.id)会忽略NULL值,无角色关联的Editor对应的roles.id为NULL,统计结果为0。
方式2:子查询排除法
先查询所有有角色关联的Editor ID,再排除这些ID得到目标结果:
Editor.where.not(id: Editor.joins(:roles).select('editors.id'))
方式3:计数器缓存(推荐高频查询场景)
如果需要频繁执行该查询,推荐添加计数器缓存提升性能:
- 生成迁移添加计数器字段:
rails generate migration AddRolesCountToEditors roles_count:integer default:0 rails db:migrate
- 修改Editor模型启用计数器缓存:
class Editor < ApplicationRecord has_many :editor_roles, dependent: :destroy has_many :roles, through: :editor_roles counter_cache :roles_count end
同时确保中间表EditorRole的关联配置:
class EditorRole < ApplicationRecord belongs_to :editor, counter_cache: :roles_count belongs_to :role end
之后查询会非常高效:
Editor.where(roles_count: 0)
内容的提问来源于stack exchange,提问作者Amir El-Bashary
相关产品推荐
相关产品推荐

