【发布时间】:2018-01-11 00:19:12
【问题描述】:
目前我有这个查询来拉出所有有头像的用户:
@users = User.all.order('RANDOM()').where.not(avatar: nil)
但是我还需要检查有帖子的用户。由于帖子位于不同的表格中,我该怎么做?
谢谢。
【问题讨论】:
标签: sql ruby-on-rails ruby ruby-on-rails-5
目前我有这个查询来拉出所有有头像的用户:
@users = User.all.order('RANDOM()').where.not(avatar: nil)
但是我还需要检查有帖子的用户。由于帖子位于不同的表格中,我该怎么做?
谢谢。
【问题讨论】:
标签: sql ruby-on-rails ruby ruby-on-rails-5
您可以只使用 User 和 Post 之间的关联(如果 Post 是您的模型),这将检查两种情况下的外键和主键是否匹配,最终检查用户是否记录了一些 Post:
User.order('RANDOM()').joins(:posts).where.not(avatar: nil)
# SELECT "users".*
# FROM "users"
# INNER JOIN "posts" ON
# "posts"."user_id" = "users"."id"
# WHERE ("users"."avatar" IS NOT NULL) ORDER BY RANDOM()
通过其他方式,您可以检查关联模型(依赖于用户的模型)的 id 是否不为零,这意味着它作为关联记录存在,例如:
User.order('RANDOM()').joins(:posts).where.not(avatar: nil)
.where.not(posts: { id: nil })
【讨论】:
GROUP BY 子句:group('users.id')。
INNER JOIN "posts" ON "posts"."user_id" = "users"."id" 不会将其添加到查询结果中。您还可以尝试结合 distinct 和 where 来检查这两个属性 User.distinct.joins(:posts).where.not(avatar: nil, posts: { id: nil })。
让用户同时拥有头像和帖子的一种方法是使用 SQL 的 EXISTS 运算符。然后我们可以利用 ActiveRecord 的作用域使这些查询可重用:
# app/models/user.rb
class User < ApplicationRecord
scope :with_avatar, -> { where.not(avatar: nil) }
scope :with_posts, -> { where('EXISTS(SELECT 1 FROM posts WHERE user_id = users.id)') }
end
现在您可以在控制器中执行以下操作:
@users = User.order('RANDOM()').with_avatar.with_posts
希望这会有所帮助!
【讨论】: