Хотя другие ответы верны, в текущих версиях Mongoid метод include - лучший способ достичь желаемых результатов.В предыдущих версиях, где include не был доступен, я нашел способ избавиться от проблемы 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 запроса из записи судьи.в моем случае предоставление серверу разработки времени ответа:
Завершено 200 OK за 816 мс (Просмотры: 785,2 мс)
Ключом к решению этой проблемы является загрузкаПользователи и фотографии в одном запросе вместо 1 на 1 для каждого судьи.
Вы можете сделать это с помощью Mongoids IdentityMap Mongoid 2 и Mongoid 3 поддерживают эту функцию.
Сначала включите карту идентификации в файле конфигурации mongoid.yml:
development:
host: localhost
database: awesome_app
identity_map_enabled: true
Теперь измените действие контроллера для ручной загрузки пользователей и фотографий.Примечание: запись Mongoid :: Relation будет лениво оценивать запрос, поэтому вы должны вызвать to_a, чтобы фактически запросить записи и сохранить их в IdentityMap.
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 мс)
Как этоРабота?Что такое IdentityMap?
IdentityMap помогает отслеживать, какие объекты или записи уже были загружены.Поэтому, если вы получите первую запись о пользователе, IdentityMap сохранит ее.Затем, если вы попытаетесь получить того же пользователя снова, Mongoid запросит IdentityMap для пользователя, прежде чем он снова запросит базу данных.Это сохранит 1 запрос к базе данных.
Таким образом, загружая всех пользователей и фотографии, которые, как мы знаем, нам нужны для судей json, в ручных запросах, мы предварительно загружаем данные в IdentityMap одновременно.,Затем, когда судья требует, чтобы он был пользователем и фотографией, он проверяет IdentityMap и не должен запрашивать базу данных.