Especificando el orden de los resultados usando datamapper

Tengo dos modelos que van asociados. Tengo un modelo Artist y un modelo Review.

class Artist
  include DataMapper::Resource

  property :id, Serial
  property :name, String

  has n, :reviews

end

class Review
  include DataMapper::Resource

  property :id, Serial
  property :rating, Integer
  property :body, String

  belongs_to :artist
end

Mi objetivo es recuperar una variedad de artistas ordenados por la calificación promedio de las reseñas asociadas con ellos. No estoy seguro de si hay una solución de una sola línea para esto, pero mi método actual es crear una matriz con las identificaciones de los artistas ordenadas por calificación promedio. Los detalles de cómo obtengo esta matriz no son importantes para esta pregunta, pero digamos que ahora tengo una matriz.

ids_sorted_by_rating = [4,5,23,9,2,48,17,....]

Luego recupero a los artistas.

artists = Artist.all(:id => ids_sorted_by_rating)

El problema es que datamapper ordena por :id a menos que especifiques otra opción. Entonces, después de todo mi arduo trabajo para obtener ids_sorted_by_rating, todavía me queda una lista de artistas ordenados por: id.

Cualquier solución que me brinde una lista de artistas ordenados por la calificación promedio de las reseñas asociadas sería MUY apreciada. Puntos de bonificación si no necesito acceder a la base de datos un millón de veces para obtener esa lista. :)

¡Gracias y si necesita más información, solo pregunte y se la proporcionaré!

preguntado el 09 de marzo de 12 a las 22:03

2 Respuestas

AFAIK, no hay una manera fácil de ordenar por agregación en DataMapper (la forma de hacerlo en una sola consulta). Puede usar un reordenamiento de resultados del lado de la aplicación (a menos que sus conjuntos de datos sean demasiado grandes para esto):

hash = artists.index_by(&:id)
# if you do not have index_by - use a artists.inject({}){|h,a| h.merge(a.id => a)} 
ids_sorted_by_rating.map{|id| hash[id]}

respondido 09 mar '12, 23:03

Por cierto, no me olvidé de ti. Simplemente no he tenido la oportunidad de probar esto. - wuliwong

Gracias, terminé yendo en una dirección diferente del problema que estaba escribiendo para resolver esta pregunta, pero encontré este mismo problema en un lugar nuevo y esto funciona. Creo que lo que debo comenzar a hacer es crear asociaciones personalizadas en lugar de simplemente decirle a datamapper :through => Resource - wuliwong

Si solo desea mostrar los datos (por ejemplo, está creando una página web con la lista) y no va a alterar la Artists podría "hacer trampa" y usar SQL (asumiendo que está usando un almacén de datos SQL):

repository(:default).adapter.select(
'SELECT artists.*
FROM artists JOIN reviews on artists.id = reviews.artist_id
GROUP BY artists.id
ORDER BY AVG(reviews.rating)')

Esto no vuelve Artist objetos, sino una serie de Structs que tendrán todas las propiedades de un Artist, por lo que puede obtener todos los datos, pero actualizarlos no servirá de mucho. Una consulta posterior puede obtener el "real" Artist (por ejemplo, un usuario hace clic en el enlace de un artista y puede usar el id valor para consultar el correspondiente Artist objeto).

También deberá tener cuidado con los diferentes dialectos de SQL, y es posible que deba modificarlo para que funcione en cualquier DBMS que esté usando (esto funciona en Sqlite, no he probado ningún otro).

Sin embargo, la matriz estará en el orden de la calificación promedio de las reseñas de cada artista.

respondido 10 mar '12, 00:03

Pensé en tomar este camino, pero cambio entre Sqlite y Postgres dependiendo de si estoy en mi máquina local o heroku. Es bueno seguir con Datamapper directo, luego puede dar cuenta del cambio de Sqlite a Postgres en una línea. Aunque gracias Si se convierte en un problema grave de consumo de recursos en el futuro, es posible que tenga que implementar algo como esto. - wuliwong

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.