ruby-on-rails - 带有嵌入式文档的 Mongoid 急切加载

标签 ruby-on-rails optimization mongoid eager-loading

我的一些类(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/

相关文章:

ruby-on-rails - capybara Drag_to 拖动到鼠标位置而不是目标

Mongoid - 一种方式引用

ruby-on-rails - 在 MongoDB 中存储数据的有效方法 : embedded documents vs individual documents

ruby-on-rails - 用于创建的简单 Mongoid 验证! - 如何显示错误信息

html - link_to_unless_current 将类分配给禁用的(当前)链接

ruby-on-rails - 更多 Ruby 风格的编码方式?

ruby-on-rails - Rails - 阻止 Internet Explorer

mysql - 优化复杂的 SQL 查询

iphone - 代码或编译器 : optimizing a IIR filter in C for the iPhone 4 and later

java - 以下代码的最佳解决方案可减少运行时间