Вопрос

Я использую мондоид для работы с MongoDB в рельсах.

Что я ищу что-то вроде активной записи include. Отказ В настоящее время я не смог найти такой метод в Mongoid Orm.

Кто-нибудь знает, как решить эту проблему в мондоиде или, возможно, в Монгомапене, которая известен как другая хорошая альтернатива.

Это было полезно?

Решение

Обновлять: Прошло два года с тех пор, как я разместил этот ответ, и все изменилось. Видеть Ответ Tybro0103 для деталей.


Старый ответ

На основании документации обоих водителей ни одна из них не поддерживает то, что вы ищете. Вероятно, потому что Это не решит ничего.

То :include Функциональность ActiveRecord решает проблему N + 1 для Базы данных SQL. Отказ Рассказывая Activerecord, связанные с таблицыми, которые включают, он может построить один запрос SQL, используя JOIN заявления. Это приведет к одному вызову базы данных независимо от количества таблиц, которые вы хотите запросить.

Mongodb только позволяет вам Запрос одного коллекции за раз. Отказ Это не поддерживает ничего подобного JOIN. Отказ Итак, даже если вы могли бы сказать монгуида, какие другие коллекции должны включать, это все равно придется выполнить отдельный запрос для каждой дополнительной коллекции.

Другие советы

Теперь, когда прошло некоторое время, Mongoid действительно добавил поддержку для этого. Смотрите раздел «Голе» здесь:
http://docs.mongodb.org/ecosystem/tutorial/ruby-mongoid-tutorial/#ager-loading.

Band.includes(:albums).each do |band|
  p band.albums.first.name # Does not hit the database again.
end

Я хотел бы указать:

  1. Рельсы :include не делает присоединение
  2. SQL и Mongo оба нуждаются в нетерпеливой загрузке.
  3. Проблема N + 1 происходит в этом случае сценария (запрос, генерируемый внутри цикла):

.

<% @posts.each do |post| %>
  <% post.comments.each do |comment| %>
    <%= comment.title %>
  <% end %>
<% end %>

Похоже, ссылка на запись @amrnt была объединена в мондоид.

Хотя другие ответы верны, в текущих версиях Mongoid Aclude Method - лучший способ достижения желаемых результатов. В предыдущих версиях, где входят не доступен, я нашел способ избавиться от N + 1 выпуск и думал, что стоит упомянуть.

В моем случае это была проблема N + 2.

class Judge
  include Mongoid::Document

  belongs_to :user
  belongs_to :photo

  def as_json(options={})
    {
      id: _id,
      photo: photo,
      user: user
    }
  end
end

class User
  include Mongoid::Document

  has_one :judge
end

class Photo
  include Mongoid::Document

  has_one :judge
end

Действие контроллера:

def index
  @judges = Judge.where(:user_id.exists => true)
  respond_with @judges
end

Это AS_JSON Ответ приводит к выпуску запроса N + 2 из рекорда судьи. В моем случае дает Dev Server время отклика:

Завершено 200 ОК в 816 мс (просмотры: 785,2 мс)

Ключ для решения этой проблемы состоит в том, чтобы загрузить пользователей и фотографии в одном запросе вместо 1 на 1 за судью.

Вы можете сделать это использование Mongoids IdentityMap Монгоид 2. и Монгоид 3. Поддержите эту функцию.

Сначала включите карту удостоверения личности в файле конфигурации Mongoid.yml:

development:
  host: localhost
  database: awesome_app
  identity_map_enabled: true

Теперь измените действие контроллера, чтобы вручную загрузить пользователей и фотографии. ПРИМЕЧАНИЕ. Запись Mongoid :: Conlation Lazy будет наращивать запрос, чтобы вы должны позвонить to_a, чтобы фактически запрашивать записи и хранить их в идентификаторе.

def index
  @judges ||= Awards::Api::Judge.where(:user_id.exists => true)
  @users = User.where(:_id.in => @judges.map(&:user_id)).to_a
  @photos = Awards::Api::Judges::Photo.where(:_id.in => @judges.map(&:photo_id)).to_a
  respond_with @judges
end

Это приводит к тому, что только в 3 запросах. 1 Для судей, 1 для пользователей и 1 для фотографий.

Завершено 200 ОК в 559 мс (просмотры: 87,7 мс)

Как это работает? Что такое идентификатор?

Идентификатор помогает отслеживать, какие объекты или записи уже загружены. Поэтому, если вы извлечь первую запись пользователя, идентификатор будет хранить его. Затем, если вы попытаетесь получить один и тот же пользователь снова Mongoid, запросили идентификатор для пользователя, прежде чем он запрашивает базу данных снова. Это сохранит 1 запрос в базе данных.

Поэтому, загрузка всех пользователей и фотографий, мы знаем, что мы хотим для судей JSON в ручных запросах, мы предварительно загружаем данные в идентификатор все сразу. Затем, когда судья требует, чтобы он пользователь и фото, он проверяет идентификатор и не нужно запросить базу данных.

Activerecord. :include как правило, не делает полное присоединение к заполнению объектов Ruby. Это делает два звонка. Во-первых, чтобы получить родительский объект (скажем, пост), затем второй вызов, чтобы потянуть связанные объекты (комментарии, которые принадлежат к посту).

Монгоид работает по существу одинаково для ссылочных ассоциаций.

def Post
    references_many :comments
end

def Comment
    referenced_in :post
end

В контроллере вы получите сообщение:

@post = Post.find(params[:id])

По вашему мнению, вы идете за комментарию:

<%- @post.comments.each do |comment| -%>
    VIEW CODE
<%- end -%>

Монгоид найдет пост в коллекции. Когда вы попадаете в комментарии ITERATOR, он делает один запрос для получения комментариев. Монгоид обернут запрос в курсоре, так что это настоящий итератор и не перегружает память.

Монгоидный ленивый загружает все запросы, чтобы позволить этому поведению по умолчанию. То :include Тег не нужен.

Это может помочь https://github.com/flyerhzm/mongoid-Ager-loading.

Вам нужно обновить вашу схему, чтобы избежать этого N + 1, в MongoDB нет никакого решения для выполнения некоторого решения.

Встраивать детальные записи / документы в главную запись / документ.

В моем случае у меня не было всей коллекции, кроме объекта того, что вызвало N + 1 (пуля говорит, что).

Так вместо того, чтобы написать ниже, вызывает N + 1

quote.providers.officialname

Я написал

Quote.includes(:provider).find(quote._id).provider.officialname

Это не вызывало проблем, но оставило меня задуматься, если я повторил себя или проверяю N + 1 ненужным для моноида.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top