Pregunta

Estoy usando Mongoid trabajar con MongoDB en Rails.

Lo que estoy buscando es algo así como activa include registro. Actualmente no pude encontrar tal método en el ORM MongoId.

conozco a nadie cómo resolver este problema en MongoId o tal vez en MongoMapper, que se conoce como otra buena alternativa.

¿Fue útil?

Solución

Actualización: ya han pasado dos años desde que he publicado esta respuesta y las cosas han cambiado. Ver de tybro0103 respuesta para obtener más detalles.


Respuesta Viejo

Sobre la base de la documentación de los dos pilotos, ninguno de ellos es compatible con lo que estás buscando. Probablemente porque no resolvería nada .

La funcionalidad :include de ActiveRecord resuelve el problema N + 1 para SQL bases de datos . Al decirle que ActiveRecord tablas relacionadas para incluir, se puede construir una sola consulta SQL, mediante el uso de declaraciones JOIN. Esto resultará en una sola llamada base de datos, independientemente de la cantidad de tablas que desea consultar.

MongoDB sólo le permite a consulta una sola colección a la vez . No es compatible con cualquier cosa como un JOIN. Así que incluso si se podría decir, que Mongoid otras colecciones que tiene que incluyen, todavía tendría que realizar una consulta independiente para cada colección adicional.

Otros consejos

Ahora que ha pasado algún tiempo, Mongoid ha añadido efectivamente apoyo a esta. Vea la sección "Eager Cargando" aquí:
http://docs.mongodb.org/ecosystem/tutorial / rubí MongoId-tutorial / # deseosos de carga

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

Me gustaría señalar:

  1. :include Rails no hacer un join
  2. SQL y Mongo tanto necesitan carga ansiosa.
  3. El N + 1 problema que ocurre en este tipo de escenario (consulta generada dentro de circular):

.

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

Parece que el vínculo que @amrnt publicada se fusionó con Mongoid.

Aunque las otras respuestas son correctas, en versiones actuales de Mongoid la incluye método es la mejor manera de lograr los resultados deseados. En versiones anteriores, donde no estaba disponible incluye he encontrado una manera de deshacerse de la cuestión n + 1 y pensé que era digno de mención.

En mi caso fue un tema + 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

acción del controlador:

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

Esta respuesta as_json resultados en un tema de consulta n + 2 desde el registro juez. en mi caso dando el servidor dev un tiempo de respuesta:

Completado 200 OK en 816ms (Vistas: 785.2ms)

La clave para resolver este problema consiste en cargar los usuarios y las fotos en una sola consulta en lugar de 1 por 1 por el juez.

Se puede hacer esto utilizando Mongoids IdentityMap Mongoid 2 y Mongoid 3 soporta esta característica

En primer giro en el mapa de identidad en el fichero de configuración mongoid.yml:

development:
  host: localhost
  database: awesome_app
  identity_map_enabled: true

Ahora cambie la acción del controlador para cargar manualmente los usuarios y fotos. Nota: El registro Mongoid :: Relación con pereza evaluará la consulta por lo que debe llamar para consultar to_a realidad los registros y los han almacenado en la 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

Este resultado en sólo 3 Total queries. 1 para los jueces, 1 para los usuarios y 1 para las fotos.

Completado 200 OK en 559ms (Vistas: 87.7ms)

¿Cómo funciona esto? ¿Qué es un IdentityMap?

Una IdentityMap ayuda a hacer un seguimiento de qué objetos o registros ya han sido cargados. Así que si usted lo trae el primer registro del usuario del IdentityMap lo almacenará. A continuación, si se intenta buscar el mismo Usuario nuevo Mongoid consulta el IdentityMap para el usuario antes de consultar la base de datos de nuevo. Esto ahorrará 1 consulta en la base de datos.

Así que mediante la carga de todos los usuarios y fotos de las que sabemos que vamos a querer para el JSON jueces en las consultas manuales que pre-cargar los datos en el IdentityMap todos a la vez. Luego, cuando el juez lo requiera de usuario y fotos comprueba el IdentityMap y no es necesario para consultar la base de datos.

ActiveRecord :include normalmente no hace un total unen para poblar objetos Ruby. La misma hace dos llamadas. En primer lugar para obtener el objeto padre (por ejemplo un mensaje) y luego una segunda llamada para tirar de los objetos relacionados (comentarios que pertenecen al mensaje).

Mongoid funciona esencialmente del mismo modo a las asociaciones que se hace referencia.

def Post
    references_many :comments
end

def Comment
    referenced_in :post
end

En el controlador que recibe el mensaje:

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

En su vista en la que iterar sobre los comentarios:

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

Mongoid encontrará el cargo en la colección. Al llegar a los comentarios iterador lo hace una sola consulta para obtener los comentarios. Mongoid envuelve la consulta en un cursor por lo que es un verdadero iterador y no sobrecargar la memoria.

MongoId cargas perezosos todas las consultas para permitir este comportamiento por defecto. La etiqueta :include es innecesaria.

Usted necesita actualizar su esquema para evitar esto N + 1 hay ninguna solución en MongoDB para hacer algunas jointure.

registros Insertar el detalle / documentos en el registro maestro / documento.

En mi caso no tenía toda la colección, sino un objeto de la misma que causó n + 1 (bala cuenta!).

Así que en lugar de escribir debajo de la cual hace que n + 1

quote.providers.officialname

he escrito

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

Esto no fue un problema, pero me dejó pensando si yo repetí o comprobar n + 1 es innecesario para MongoId.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top