Хотя другие ответы верны, в текущих версиях Mongoid метод включения - лучший способ достичь желаемых результатов. В предыдущих версиях, где включение было недоступно, я нашел способ избавиться от проблемы 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 из записи Judge. в моем случае предоставление серверу разработки времени отклика:
Выполнено 200 OK за 816 мс (просмотры: 785,2 мс)
Ключом к решению этой проблемы является загрузка пользователей и фотографий в одном запросе, а не по одному на каждого судью.
Вы можете сделать это, используя 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 OK за 559 мс (просмотры: 87,7 мс)
Как это работает? Что такое IdentityMap?
IdentityMap помогает отслеживать, какие объекты или записи уже были загружены. Поэтому, если вы получите первую запись пользователя, IdentityMap сохранит ее. Затем, если вы попытаетесь снова получить того же пользователя, Mongoid запрашивает IdentityMap для пользователя, прежде чем снова запросить базу данных. Это позволит сохранить 1 запрос в базе данных.
Таким образом, загружая всех пользователей и фотографии, которые, как мы знаем, нам понадобятся для судей json в ручных запросах, мы предварительно загружаем данные в IdentityMap все сразу. Затем, когда судья требует своего пользователя и фотографию, он проверяет IdentityMap и ему не нужно запрашивать базу данных.
person
brianp
schedule
23.10.2012