首页 > 解决方案 > Rails 5.2 ActiveRecord 查询:.joins 和 .include 之间的区别

问题描述

我正在为这个新项目学习 Rails 5.2(和 MySQL),我想更多地了解joinincludes.

假设项目有一个Like模型:

<Like emoji_type user_id>

这是User模型:

<User id username banned>

假设我只想查找未被禁止 ( status != 0) 的用户的赞,并按 . 对它们进行分组emoji_type

这是不过滤被禁止用户的旧查询,它使用includes

@likes_map = likes.where.not(emoji_type: nil)
  .includes(:user)
  .group_by(&:emoji_type)

这是我到目前为止的查询(有效),它使用joins

@likes_map = likes.joins(:user).select(:emoji_type, :username, :status)
  .where("emoji_type IS NOT NULL")
  .where("status != 0")
  .group_by(&:emoji_type)

我注意到includes返回的结果与joins尝试将内容记录到控制台时的结果存在一些差异:

# includes
p @likes.username => nil
p @likes.user.name => username

# joins
p @likes.username => username
p @likes.user.name => nil

# with both joins and includes,
# this just returns a Like record, 
# with no info from User:
p @likes

标签: mysqlruby-on-railsruby-on-rails-5

解决方案


  • joins是一个实际的 SQL 联合,允许您查询嵌套模型。一个连接的可用数据是两个连接表的所有数据。
Like.joins(:user).where(user: { email: "your@email.com"})

如果有多次相同的名称(例如时间戳created_at/ updated_at),您可以使用之前的表访问每个名称,并使用类似的 where 子句joins(:user).where('users.created_at < ?', Time.zone.now)

  • includes用于预先加载嵌套数据以避免n+1查询。它不另一个表连接(这就是likes.username返回的原因nil(它实际上应该引发错误,除非您在模型上委托了我猜的属性)。
Like.includes(:user).map do |l|
  l.user.email
end

如有必要,您可以同时使用两者

Like.joins(:user).includes(:user).where(user: { email: "your@email.com"}).map do |l|
  l.user.id
end

# just for example because there is an easier way to do it of course
# Like.joins(:user).where(user: { email: "your@email.com"}).pluck(:id)

我想说这应该回答你所有的 3 个问题。


推荐阅读