我的一些类(class):
class User
embeds_many :notifications
field :first_name
field :last_name
def name{ "#{first_name} #{last_name}" }
class Notification
embedded_in :user
belongs_to :sender, class_name: "User", inverse_of: nil
现在在我看来,我实现了一个用于通知的小型邮箱系统。但是,它目前正在访问数据库的 N+1 倍:
<% current_user.notifications.sort{...}.each do |notif|%>
...
<%= notif.sender.name if notif.sender %>
这里的问题是 notif.sender.name
导致 N
命中数据库。我能以某种方式预加载/急切加载这个吗?像 current_user.notifications.includes(:sender)
这样的东西(但会起作用 :D)
我目前只需要发件人姓名。
最佳答案
我认为你在这里运气不好。 Mongoid 有如下错误消息:
Eager loading in Mongoid only supports providing arguments to M.includes that are the names of relations on the M model, and only supports one level of eager loading. (ie, eager loading associations not on the M but one step away via another relation is not allowed).
请特别注意最后一个括号内的句子:
eager loading associations not on the M but one step away via another relation is not allowed
嵌入是一种关系,但您想将 includes
应用于嵌入关系,这对 Mongoid 来说太过分了。
fine manual确实是这样说的:
This will work for embedded relations that reference another collection via
belongs_to
as well.
但这意味着您将在嵌入关系上调用 includes
而不是嵌入模型的内容。在您的情况下,这意味着您可以为每组嵌入关系急切加载发件人通知:
current_user.notifications.includes(:sender).sort { ... }
这仍然会给您留下 N+1
问题,即预加载应该绕过但您的 N
会更小。
如果这仍然太重,那么您可以将名称反规范化到每个嵌入文档中(即复制它而不是通过 sender
引用它)。当然,如果允许人们更改姓名,则您需要保留副本。
关于ruby-on-rails - 带有嵌入式文档的 Mongoid 急切加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29472487/