2012-09-05 10 views
11

puedo usar lo siguiente:¿Cómo puedo contar el resultado de una consulta ActiveGroup .group? Encadenando .count devuelve un hash

User.where("zip_code = '48104'").group('users.id').count 

Para obtener los hashes como:

{195=>1, 106=>1, 120=>1, 227=>1, 247=>1, 264=>1, 410=>1} 

¿Hay una manera que puedo contar estos hashes, y acaba de regresar , en lugar del resultado anterior?

Sé que esto no tiene sentido en el escenario anterior, y puedo hacerlo simplemente al no usar la cláusula del grupo. Pero estoy trabajando en una consulta más compleja, donde tengo que implementar esto. Gracias por adelantado.

+2

Puede obtener la longitud de * any * hash con '.length' – meagar

+1

@meagar: Sin embargo, eso requiere devolver todos los registros como objetos y luego contarlos. Es un poco un cerdo de rendimiento. –

Respuesta

19

Probar:

User.where("zip_code = '48104'").group('users.id').count.length 
+0

cualquier forma de hacer esto sin tirar todos los registros de la base de datos? – orourkedd

+0

Puede hacerlo con una subselección en SQL sin formato. Necesitará usar la conexión de base de datos sin procesar para hacer eso: http://apidock.com/rails/ActiveRecord/Base/connection – robbrit

+0

Es hackish, pero otra forma de reducir la cantidad extraída de la base de datos es lanzar un .select ('id') scope, para evitar convocar a las otras columnas. –

3

Si desea agregar los valores de las claves juntos entonces:

{key1: 1, key2: 2}.values.inject(:+) # => 3 

Si lo que desea es el número de teclas a continuación:

{key1: 1, key2: 2}.length # => 2 
+0

+1 ¡Funciona! Gracias. – Myxtic

8

La respuesta aceptada no es escalable. El uso del método de @britbrit en una consulta con 25,000 usuarios que coinciden generará 25,000 resultados (es decir, una matriz con 25,000 elementos) en la memoria y luego contará la matriz de elementos. Aquí es un método que va a hacerlo sin tirar todos esos datos:

def count_query(query) 
    query = "SELECT count(*) AS count_all FROM (#{query.to_sql}) x" 
    ActiveRecord::Base.connection.execute(query).first.try(:[], 0).to_i 
end 

Se utiliza la siguiente manera:

query = User.where("zip_code = '48104'").group('users.id') 
count = count_query(query) 

Esto funciona para mí usando MySQL, por cierto.

Fue inspirado por este tipo: https://github.com/mrbrdo/active_record_group_count/blob/master/lib/active_record_group_count/scope.rb

0

Otra forma, útil si los valores pueden ser> 1.

User.where("zip_code = '48104'").group('users.id').count.values.sum 
2

Como se ha dicho antes por orourkedd la respuesta aceptada no es grande cuando se trata de con una gran cantidad de registros. Recientemente, me encontré con este problema y tengo tablas grandes que definitivamente no quiero cargar en la memoria. Así que aquí está lo que funciona para mí.

users=User.where("zip_code = '48104'").group('users.id') 
user_count=User.where(id: users.select(:id)).count 

Rails manejará la parte users.select como una subconsulta. Esto funciona con Rieles 4

Cuestiones relacionadas