2011-03-04 16 views
8

¿Cómo puedo crear consultas de relaciones activas en Rails 3 que se agregan por segmento de tiempo?Cómo obtener datos agregados por intervalo de tiempo (suma, promedio, mínimo, máximo, etc.) en Rails 3

Me gustaría generar consultas que, por cada intervalo de n minutos, pueden devolver min, max, avg, sum, count, por cada muestra de un contador con un nombre particular.

create_table "samples" 
    t.integer "counter_id" 
    t.string "name" 
    t.float "value" 
    t.datetime "created_at" 
end 
+0

Discos de tiempo a que se refiere created_at de 'muestra reducida? Y 'contador has_many: samples'? ¿Y necesita encontrar max, min, etc. de 'value'? – fl00r

+0

Hola fl00r, si exactamente. Y por divisiones de tiempo quiero decir que me gustaría agregar todos los valores de muestra dentro de cada intervalo (por ejemplo: intervalos de 1 o 10 segundos) en un solo valor resultante para cada intervalo, pero al mismo tiempo recuperar muchos intervalos sin una consulta separada para cada uno de los intervalos. – ebeland

Respuesta

4

Desafortunadamente, nunca he usado Postgres, por lo que esta solución funciona en MySQL. Pero creo que puedes encontrar análogos de Postgres.

class Counter < ActiveRecord::Base 
    has_many :samples do 
    # default 30 minutes 
    def per_time_slice(slice = 30) 
     start = "2000-01-01 00:00:00" 
     self.select("*, 
        CONCAT(FLOOR(TIMESTAMPDIFF(MINUTE,'#{start}',created_at)/#{slice})*#{slice}, 
        (FLOOR(TIMESTAMPDIFF(MINUTE,'#{start}',created_at)/#{slice})+1)*#{slice}) as slice, 
        avg(value) as avg_value, 
        min(value) as min_value, 
        max(value) as max_value, 
        sum(value) as sum_value, 
        count(value) as count_value"). 
        group("slice").order("slice") 
    end 
    end 
end 

Uso

counter = find_some_counter 
samples = counter.samples.per_time_slice(60).where(:name => "Bobby") 
samples.map(&:avg_value) 
samples.map(&:min_value) 
samples.map(&:max_value) 

etc

+0

Esto se ve muy fantástico. ¡Gracias! – ebeland

+2

Cambiar CONCAT (bla, bla) en bla || bla para que sea más agradable a PgSQL. – thomasfedb

+0

Disculpas, esta fue una gran respuesta, y me di cuenta hoy que no había tocado la casilla de aceptar. – ebeland

1

Esto debe hacer el truco:

Samples.where("SQL for the time slice goes here").where(:name, "Views").average(:value) 

También puede intercambiar promedio para cualquiera de mínimo, máximo y suma.

+0

Con lo que usted propone, si estaba recuperando 1000 segmentos de tiempo pequeños, ¿habría entonces 1000 consultas? – ebeland

+0

Sí, la única forma de alejarme de esto es la magia de db extraña ... – thomasfedb

+0

Agregué una recompensa ya que creo que necesito entrar en la extraña magia de DB, ya que 1000 consultas por solicitud serán demasiado costosas. Upvoted por darme algunos de los rieles 3 respuesta ... Gracias- – ebeland

Cuestiones relacionadas