Rails中如何查询获取所有用户列表及各自的文章数量
问题根源
你写的查询用joins(:posts)默认生成INNER JOIN,只返回存在关联Post的用户,自然会把没发过文章的用户过滤掉。之前用include的方案是预加载全量关联数据,确实会把所有Post记录载入内存,资源浪费严重。
正确实现
用左外连接(LEFT OUTER JOIN)替代内连接即可,聚合计算直接在数据库层完成,不会加载全量Post数据,性能远高于预加载方案。
Rails 5+ 原生写法
Rails 5 内置了左连接方法left_joins(别名left_outer_joins),代码如下:
User.left_joins(:posts) .select('users.*, COUNT(posts.id) AS post_count') .group('users.id')
查询返回的每个User对象都会自带post_count属性,没有发布过文章的用户该属性值为0,完全覆盖全量用户的统计需求。
原理说明:
- 左外连接会保留users表的所有记录,就算用户没有对应Post也不会被剔除
COUNT(posts.id)会自动忽略连接生成的NULL值,不会把无Post的用户统计为1或者报错- 最终查询结果只包含用户字段和聚合后的计数值,不会把所有Post记录载入内存,没有额外性能损耗
Rails 4及更低版本适配
老版本没有内置左连接语法,可以手动写SQL片段实现:
User.joins('LEFT OUTER JOIN posts ON posts.user_id = users.id') .select('users.*, COUNT(posts.id) AS post_count') .group('users.id')
踩坑提示
如果要统计符合特定条件的文章数(比如仅统计已发布、未删除的文章),不要直接在主查询的where条件里加Post的过滤规则,否则会把无匹配Post的用户过滤掉。这类场景要把过滤条件写到LEFT JOIN的ON子句里,或者通过带条件的关联来实现。
内容的提问来源于stack exchange,提问作者leonchik12
相关产品推荐
相关产品推荐

