Especificando el orden de los resultados usando datamapper
Frecuentes
Visto 586 veces
2
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é!
2 Respuestas
1
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
0
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 ruby associations datamapper or haz tu propia pregunta.
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