En este artículo, aprenderá los conceptos básicos de las consultas de Registro Activo y aprenderá algunos aspectos básicos sobre SQL en el camino. Está dirigido a principiantes que desean comenzar a aprender más sobre las consultas de bases de datos en Ruby on Rails.
Registro activo se utiliza para consultar la base de datos. Se puede utilizar con SQL, PostgresSQL y SQLite. Para recuperar registros de su base de datos, tiene varios métodos de búsqueda a su disposición. Lo bueno de ellos es que puede ahorrarse la molestia de escribir SQL en bruto.
¿Qué hace un método de buscador realmente? Básicamente tres cosas: sus opciones proporcionadas se convierten en una consulta SQL. Luego, la consulta SQL se ejecuta y recupera los datos de la base de datos. Además, para cada fila en esa lista de resultados, obtenemos objetos Ruby recién instanciados del modelo que corresponde con la consulta.
Si no has jugado con SQL antes, haré todo lo posible para mantener las cosas simples y presentarte lo más básico. Siga los ejemplos de SQL y trate de dar sentido a estas consultas simples. SQL no es realmente una ciencia espacial, la sintaxis solo requiere un poco de tiempo para acostumbrarse. Con suerte, esto abrirá su apetito para buscar algunos tutoriales útiles que llenen los espacios en blanco..
Echemos un vistazo a algunos métodos que están a su disposición:
encontrar
primero
último
encontrar por
todos
encontrar
find_in_batches
dónde
orden
límite
compensar
grupo
teniendo
Todos estos devolverán una instancia de ActiveRecord :: Relación
. ¿Un qué? Es una clase que tiene espacio de nombre dentro del módulo ActiveRecord
, y nos permite llamar a múltiples métodos de consulta y encadenarlos. Este objeto es el corazón de la sintaxis de consulta utilizada en Rails. Revisemos la clase de tal objeto y veamos por nosotros mismos:
Agent.where (nombre: 'James Bond'). Class # => ActiveRecord :: Relation
encontrar
Este método le permite proporcionar la identificación principal de un objeto y recupera ese único objeto para usted. Si proporciona una matriz de identificadores, también puede recuperar varios objetos.
bond = Agent.find (7)
SELECCIONE "agentes". * DE "agentes" DONDE "agentes". "Id" =? LÍMITE 1 [["id", 7]]
Esta línea de SQL indica que desea seleccionar todo (*
) atributos de la agentes
tabla y "filtre" solo el registro con el id 7. Un límite hace que solo devuelva un solo registro de la base de datos.
primero
, último
Como era de esperar, estos le darán los primeros y últimos registros que se pueden identificar por su clave principal. La parte interesante, sin embargo, es que puede proporcionar un número opcional que le devuelve el primero o el último de ese número de registros.
enemy_agents = SpectreAgent.first (10) enemy_agents = SpectreAgent.last (10)
Bajo el capó, está proporcionando un nuevo límite para el número que proporciona y ordenándolo en forma ascendente o descendente.
SELECCIONE "spectreagents". * FROM "spectreagents" ORDER BY "spectreagents". "Id" ASC LIMIT 10 SELECT "spectreagents". * FROM "spectreagents" ORDER BY "spectreagents". "Id" DESC LIMIT 10
encontrar por
Este buscador devuelve el primer objeto que coincide con la condición que proporcionó.
bond = Agent.find_by (last_name: 'Bond')
SELECCIONE "agentes". * FROM "agentes" DONDE "agentes". "Last_name" =? LÍMITE 1 [["last_name", "Bond"]]
Obviamente, a menudo necesitamos iterar sobre una colección de objetos con alguna agenda. Recuperar un solo objeto o unos pocos seleccionados a mano es bueno, pero la mayoría de las veces, queremos que Active Record recupere objetos en lotes.
Mostrar a los usuarios todo tipo de listas es el pan y la mantequilla para la mayoría de las aplicaciones de Rails. Lo que necesitamos es una herramienta poderosa con una API conveniente para recolectar estos objetos para nosotros, con suerte de una manera que nos permita evitar escribir el SQL involucrado la mayor parte del tiempo.
todos
mi6_agents = Agentes.todos
SELECCIONE "agentes". * DE "agentes"
Este método es útil para colecciones relativamente pequeñas de objetos. Trate de imaginar hacer esto en una colección de todos los usuarios de Twitter. No, no es una buena idea. Lo que queremos en cambio es un enfoque más preciso para tamaños de mesa más grandes.
¡Ir a buscar a toda la mesa no va a escalar! ¿Por qué? Como no solo pediríamos un montón de objetos, también tendríamos que crear un objeto por fila en esta tabla y colocarlos en una matriz en la memoria. Espero que esto no suene como una buena idea! Entonces, ¿cuál es la solución para esto? Lotes Estamos dividiendo estas colecciones en lotes que son más fáciles de procesar en la memoria. Woohoo!
Echemos un vistazo a encontrar
y find_in_batches
. Ambos son similares pero se comportan de manera diferente en la forma en que producen los objetos en bloques. Aceptan una opción para regular el tamaño del lote. El valor predeterminado es 1.000..
encontrar
NewRecruit.find_each do | recluta | recruit.start_hellweek end
SELECCIONE "newrecruits". * FROM "newrruits" ORDER BY "newrecuits". "Id" ASC LIMIT 1000
En este caso, recuperamos un lote predeterminado de 1,000 nuevos reclutas, los entregamos al bloque y los enviamos al infierno semana, uno por uno. Debido a que los lotes están dividiendo las colecciones, también podemos decirles dónde comenzar a través de comienzo
. Digamos que queremos procesar 3,000 posibles reclutas de una vez y queremos comenzar con 4,000.
NewRecruit.find_each (inicio: 4000, batch_size: 3000) hacer | reclutar | recruit.start_hellweek end
SELECCIONE "newrecruits". * FROM "newrruits" WHERE ("newrruits". "Id"> = 4000) ORDENADO POR "newrruits". "Id" ASC LIMIT 3000
Para reiterar, primero recuperamos un lote de 3,000 objetos Ruby y luego los enviamos al bloque. comienzo
nos permite especificar la identificación de los registros donde queremos comenzar a buscar este lote.
find_in_batches
Éste entrega su lote como una matriz al bloque; lo pasa a otro objeto que prefiere tratar con colecciones. El SQL es el mismo aquí..
NewRecruit.find_in_batches (inicio: 2700, batch_size: 1350) do | reclutas | field_kitchen.prepare_food (reclutas) final
dónde
Necesitamos repasar dónde
antes de seguir adelante Esto nos permite especificar condiciones que limitan el número de registros devueltos por nuestras consultas, un filtro para "dónde" recuperar registros de la base de datos. Si has jugado con SQL DÓNDE
cláusulas, entonces es posible que simplemente te sientas como en casa, lo mismo con esta envoltura de Ruby.
En SQL, esto nos permite especificar a qué fila de la tabla queremos afectar, básicamente cuando cumple con algún tipo de criterio. Esta es una cláusula opcional, por cierto. En el SQL sin formato a continuación, seleccionamos solo los reclutas que son huérfanos a través de DÓNDE
.
Seleccione una fila específica de una tabla.
SELECCIONAR * DE LOS RECLUTOS DONDE FamilyStatus = 'Huérfano';
Vía dónde
, Puede especificar condiciones con cadenas, hashes o matrices. Al juntar todo esto, Active Record le permite filtrar condiciones como las siguientes:
promising_candidates = Recruit.where ("family_status = 'orphan'")
SELECCIONE "reclutas". * DE "reclutas" DONDE (family_status = 'huérfano')
Bastante limpio, ¿verdad? Quiero mencionar que esto sigue siendo una operación de búsqueda; simplemente especificamos cómo queremos filtrar esta lista de inmediato. De la lista de todos los reclutas, esto devolverá una lista filtrada de candidatos huérfanos. Este ejemplo es una condición de cadena. Manténgase alejado de las condiciones de cadena pura, ya que no se consideran seguras debido a su vulnerabilidad a las inyecciones de SQL.
En el ejemplo anterior, ponemos la huérfano
Variable en la cadena con las condiciones. Esto se considera una mala práctica porque no es seguro. Necesitamos escapar de la variable para evitar esta vulnerabilidad de seguridad. Debería leer acerca de la inyección SQL si esta es una noticia total para usted: su base de datos podría depender de ello.
promising_candidates = Recruit.where ("family_status =?", 'huérfano' ")
los ?
será reemplazado como el valor de condición por el siguiente valor en la lista de argumentos. Así que el signo de interrogación es básicamente un marcador de posición. También puede especificar múltiples condiciones con múltiples ?
y encadenarlos juntos. En un escenario de la vida real, usaríamos un hash params como este:
promising_candidates = Recruit.where ("family_status =?", params [: reclutas])
Si tiene un gran número de condiciones variables, debe usar condiciones de marcador de posición clave / valor.
promising_candidates = Recruit.where ("family_status =: preferred_status AND iq> =: required_iq AND charming =: lady_killer", preferred_status: 'orphan', required_iq: 140, lady_killer: true)
SELECCIONE "reclutas". * FROM "reclutas" DONDE (family_status = 'huérfano' AND iq> = 140 AND lady_killer = true)
El ejemplo anterior es tonto, por supuesto, pero muestra claramente los beneficios de la notación de marcador de posición. La notación hash, en general, es definitivamente la más legible..
promising_candidates = Recruit.where (estado_familia: 'huérfano') promising_candidates = Recruit.where ('charming': true)
Como puedes ver, puedes ir con símbolos o cadenas para ti. Cerremos esta sección con rangos y condiciones negativas a través de NO.
promising_candidates = Recruit.where (cumpleaños: ('1994-01-01'… '2000-01-01'))
Dos puntos y puedes establecer cualquier rango que necesites..
promising_candidates = Recruit.where.not (carácter: 'cobarde')
Puedes meter el no
sobre la dónde
para filtrar a todos los cobardes y obtener solo resultados que no tengan ese atributo específico no deseado. Bajo el capó, una !=
niega el "filtro" DONDE.
SELECCIONE "reclutas". * DE "reclutas" DÓNDE ("reclutas". "Carácter"! =?) [["Carácter", "cobarde"]]
orden
Para no aburrirte hasta morir con esto, hagamos que esto sea rápido.
candidatos = Recruit.order (: date_of_birth)
candidatos = Recruit.order (: date_of_birth,: desc)
Aplicar : asc
o : desc
para ordenarlo en consecuencia. Eso es básicamente, así que sigamos adelante.!
límite
Puede reducir el número de registros devueltos a un número específico. Como se mencionó anteriormente, la mayoría de las veces no necesitará que se devuelvan todos los registros. El siguiente ejemplo le dará los primeros cinco reclutas en la base de datos, los primeros cinco id..
five_candidates = Recruit.limit (5)
SELECCIONE "reclutas". * DESDE "reclutas" LIMITE 5
compensar
Si alguna vez te has preguntado cómo funciona la paginación bajo el capó, límite
y compensar
-en conjunción-haz el trabajo duro. límite
puede valerse por sí solo, pero compensar
depende de la primera.
La configuración de un desplazamiento es principalmente útil para la paginación y le permite omitir el número deseado de filas en la base de datos. La página dos de una lista de candidatos podría verse así:
Recruit.limit (20) .offset (20)
El SQL se vería así:
SELECCIONE "reclutas". * DE "reclutas" LÍMITE 20 DESPLAZAMIENTO 20
Una vez más, estamos seleccionando todas las columnas de la Recluta
modelo de base de datos, que limita los registros devueltos a 20 objetos Ruby de Reclutamiento de clase y saltando sobre los primeros 20.
Digamos que queremos una lista de reclutas que se agrupan por sus IQ. En SQL, esto podría verse así..
SELECCIONE "reclutas". * FROM "recluta" GROUP BY "reclutas". "Iq"
Esto le proporcionará una lista en la que verá qué posibles reclutas tienen un IQ de, digamos, 120, y luego otro grupo de, digamos, 140, y así sucesivamente, sean cuales sean sus IQ y cuántos estarían en un número específico. Así que cuando dos reclutas tienen el mismo coeficiente intelectual de 130, se agruparán.
Otra lista podría ser agrupada por posibles candidatos que sufren de claustrofobia, miedo a las alturas o que no son médicamente aptos para el buceo. La consulta de Registro Activo se vería así:
grupo
Grupo de candidatos (: iq)
Cuando contamos el número de candidatos, obtenemos un hash muy útil.
Candidate.group (: iq) .count # => 130 => 7, 134 => 4, 135 => 3, 138 => 2, 140 => 1, 141 => 1
Ahí vamos, tenemos siete posibles reclutas con un coeficiente intelectual de 130 y solo uno con 141. El SQL resultante se vería así:
SELECCIONAR COUNT (*) AS count_all, iq AS iq DE "candidatos" GRUPO POR "candidatos". "Iq"
La pieza importante es la AGRUPAR POR
parte. Como puede ver, usamos la tabla de candidatos para obtener sus ID. Lo que también puede observar a partir de este sencillo ejemplo es cuánto más convenientemente leen y escriben las versiones de Active Record. Imagina hacer esto a mano en ejemplos más extravagantes. Claro, a veces tienes que hacerlo, pero todo el tiempo es claramente un dolor que con gusto podemos evitar..
teniendo
Podemos especificar este grupo aún más usando TENIENDO
-una especie de filtro para el grupo
. En ese sentido, teniendo
es una especie de DÓNDE
cláusula para GRUPO
. En otras palabras, teniendo
depende de usar grupo
.
Recruit.having ('iq>?', 134) .group (: iq)
SELECCIONE "reclutas". * DE "reclutas" GRUPO POR "reclutas". "Iq" TIENE iq> '134'
Ahora hemos agrupado a nuestros candidatos en listas de personas que tienen un coeficiente intelectual mínimo de 135. Vamos a contarlos para obtener algunas estadísticas:
Recruit.having ('iq>?', 134) .group (: iq) .count # => 135 => 3, 138 => 2, 140 => 1, 141 => 1
SELECCIONAR CUENTA (*) AS count_all, iq AS iq FROM "reclutas" GROUP BY "reclutas". "Iq" TIENE iq> '134'
También podríamos mezclar y combinar estos y ver, por ejemplo, qué candidatos que tienen un coeficiente intelectual superior a 140 están vinculados o no en relaciones.
Recruit.having ('iq>?', 140) .group (: family_status)
SELECCIONE "reclutas". * FROM "recluta" GROUP BY "reclutas". "Estado_familia" QUE TIENE iq> '140'
Contar estos grupos ahora es muy fácil:
Recruit.having ('iq>?', 140) .group (: family_status) .count # => "married" => 2, "single" => 1
SELECCIONAR CUENTA (*) AS count_all, family_status AS family_status DE "reclutas" GROUP BY "reclutas". "Family_status" HAVING iq> '140'
Espero que este sea un primer vistazo útil a lo que Active Record tiene para ofrecer para que sus esfuerzos de consulta sean lo más legibles y convenientes posible. En general, diría que es un excelente envoltorio que evita que usted escriba SQL a mano la mayor parte del tiempo.
En el siguiente artículo, veremos un par de buscadores más involucrados y ampliaremos lo que hemos aprendido hasta ahora..