mysql - Rails 5.2 ActiveRecord 查询:.joins 和 .include 之间的区别
问题描述
我正在为这个新项目学习 Rails 5.2(和 MySQL),我想更多地了解join
和includes
.
假设项目有一个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
- 为什么两个查询返回的对象不同?
- 为什么我
joins
在登录控制台时看不到查询中的任何用户信息? - 我知道这
includes
会做一些急切的加载。我的joins
查询是否以某种方式效率低下?
解决方案
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 个问题。
推荐阅读
- yocto - 每层 yocto 的 BB_NO_NETWORK 访问权限。镜像外部存储库并访问本地存储库
- camunda - Camunda BPM External Task 吞下了它的重试:如何反应(例如使用条件流)?
- c - 不能在 xcode 中使用 malloc.h?
- mysql - 无法将 MySQL 8 安装到 Debian 10
- c# - Unity - 2D 瞄准鼠标,同时限制最小/最大旋转并考虑父旋转
- c# - UWP:将均衡器添加到 MediaPlayer
- java - 如何在 Firebase 数据库中检索特定子项的数据
- android - Flutter中华为站点套件中的MissingPluginException
- c# - 添加 System.Runtine 4.3.1 时对 System.ComponentModel.Composition 的 Nuget 引用不正确
- forms - 如何使yii2中表单字段小部件的值(要读取)与用户在输入文本框中看到的不同