2011-11-22 11 views
8

Con estos modelos:¿Cómo puedo encontrar registros por "recuento" de asociación utilizando raíles y mongoid?

class Week 
    has_many :proofs 
end 
class Proof 
    belongs_to :week 
end 

quiero hacer algo como:

Week.where(:proof.count.gt => 0) 

para encontrar sólo semanas que tienen varias pruebas.

Hay una respuesta que parece hacer frente a este:

Can rails scopes filter on the number of associated classes for a given field

Sin embargo, en este ejemplo, no hay ningún atributo como proof_ids en Semana desde los identificadores se almacenan con las pruebas. Esto no funciona, por ejemplo:

Week.where(:proof_ids.gt => 0) 

¿Cómo es posible esta consulta? Conceptualmente simple pero no puedo entender cómo hacer esto con mongo o mongoid.

Del mismo modo, me gustaría pedir por el número de pruebas como por ejemplo:

Week.desc(:proofs.size) 

Pero esto también no funciona.

Me doy cuenta de que un contador de caché es una opción para mis dos preguntas específicas, pero también me gustaría poder hacer la consulta.

Gracias de antemano por cualquier ayuda.

Respuesta

5

Con rieles (y sin counter_cache), se puede hacer:

class Week < ActiveRecord::Base 
    has_many :proofs 

    def self.by_proofs_size 
    sort_by { |week| week.proofs.size } 
    end 

    def self.with_at_least_n_proofs(n = 1) 
    select { |week| week.proofs.size >= n } 
    end 
end 

A pesar de que cada una de esas operaciones produce 2 consultas, esto está lejos de ser ideal.

El par de consultas se repite (=> 4 consultas para cada operación) con alcances (bug?):

scope :with_at_least_n_proofs, -> (n = 1) { select { |w| w.proofs.size >= n } } 
scope :by_proofs_size, -> { sort_by { |w| w.proofs.size } } 

Lo ideal es probablemente usar counter_cache

scope :with_at_least_n_proofs, -> (n = 1) { where('proofs_count >= ?', n) } 
scope :by_proofs_size, -> { order(proofs_count: :desc) } 
+0

Puede eliminar includes (: pruebas) para aumentar el rendimiento en una tonelada. Actualmente, está cargando todos los datos en: pruebas, cuando todo lo que realmente necesita es una consulta de recuento rápido. Pruébalo. –

+0

@RobVolk ¡Ese era un viejo código! ¡Gracias por el aviso! – Damien

+0

matará su solicitud porque recibirá todas las semanas con todas las pruebas de la base de datos en la memoria de su aplicación – antiqe

0

Disculpe si estoy muy lejos, pero ¿podría usar una simple counter_cache en la tabla de semanas? Entonces podrías hacer algo como week.proofs_count.

+0

Sí, como dije en mi pregunta, sé que counter_cache es una opción, pero prefiero hacer una consulta si es posible en este caso. Si eso no va a funcionar, definitivamente haré el contador de caché. – eagspoo

4

I don' t saber si esta es la mejor solución, ya que lo mapea a través de una matriz, pero esto hace el trabajo: (las otras soluciones mencionadas aquí me dan excepciones)

class Week < ActiveRecord::Base 

    scope :has_proofs, -> { any_in(:_id => includes(:proofs).select{ |w| w.proofs.size > 0 }.map{ |r| r.id }) } 

end 
Cuestiones relacionadas