mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-11-01 03:26:36 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			471 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			471 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| Constructor de Consultas
 | |
| ========================
 | |
| 
 | |
| > Note: Esta sección está en desarrollo.
 | |
| 
 | |
| Yii proporciona una capa de acceso básico a bases de datos como se describe en la sección
 | |
| [Objetos de Acceso a Bases de Datos](db-dao.md). La capa de acceso a bases de datos proporciona un método de bajo
 | |
| nivel (low-level) para interaccionar con la base de datos. Aunque a veces puede ser útil la escritura de sentencias
 | |
| SQLs puras, en otras situaciones puede ser pesado y propenso a errores. Otra manera de tratar con bases de datos puede
 | |
| ser el uso de Constructores de Consultas (Query Builder). El Constructor de Consultas proporciona un medio orientado a
 | |
| objetos para generar las consultas que se ejecutarán.
 | |
| 
 | |
| Un uso típico de Constructor de Consultas puede ser el siguiente:
 | |
| 
 | |
| ```php
 | |
| $rows = (new \yii\db\Query())
 | |
|     ->select('id, name')
 | |
|     ->from('user')
 | |
|     ->limit(10)
 | |
|     ->all();
 | |
| 
 | |
| // que es equivalente al siguiente código:
 | |
| 
 | |
| $query = (new \yii\db\Query())
 | |
|     ->select('id, name')
 | |
|     ->from('user')
 | |
|     ->limit(10);
 | |
| 
 | |
| //  Crear un comando. Se puede obtener la consulta SQL actual utilizando $command->sql
 | |
| $command = $query->createCommand();
 | |
| 
 | |
| // Ejecutar el comando:
 | |
| $rows = $command->queryAll();
 | |
| ```
 | |
| 
 | |
| Métodos de Consulta
 | |
| -------------------
 | |
| 
 | |
| Como se puede observar, primero se debe tratar con [[yii\db\Query]]. En realidad, `Query` sólo se encarga de
 | |
| representar diversa información de la consulta. La lógica para generar la consulta se efectúa mediante
 | |
| [[yii\db\QueryBuilder]] cuando se llama al método `createCommand()`, y la ejecución de la consulta la efectúa
 | |
| [[yii\db\Command]].
 | |
| 
 | |
| Se ha establecido, por convenio, que [[yii\db\Query]] proporcione un conjunto de métodos de consulta comunes que
 | |
| construirán la consulta, la ejecutarán, y devolverán el resultado. Por ejemplo:
 | |
| 
 | |
| - [[yii\db\Query::all()|all()]]: construye la consulta, la ejecuta y devuelve todos los resultados en formato de array.
 | |
| - [[yii\db\Query::one()|one()]]: devuelve la primera fila del resultado.
 | |
| - [[yii\db\Query::column()|column()]]: devuelve la primera columna del resultado.
 | |
| - [[yii\db\Query::scalar()|scalar()]]: devuelve la primera columna en la primera fila del resultado.
 | |
| - [[yii\db\Query::exists()|exists()]]: devuelve un valor indicando si la el resultado devuelve algo.
 | |
| - [[yii\db\Query::count()|count()]]: devuelve el resultado de la consulta `COUNT`. Otros métodos similares incluidos
 | |
|   son `sum($q)`, `average($q)`, `max($q)`, `min($q)`, que soportan las llamadas funciones de agregación. El parámetro
 | |
|   `$q` es obligatorio en estos métodos y puede ser el nombre de la columna o expresión.
 | |
| 
 | |
| Construcción de Consultas
 | |
| -------------------------
 | |
| 
 | |
| A continuación se explicará como construir una sentencia SQL que incluya varias clausulas. Para simplificarlo, usamos
 | |
| `$query` para representar el objeto [[yii\db\Query]]:
 | |
| 
 | |
| ### `SELECT`
 | |
| 
 | |
| Para formar una consulta `SELECT` básica, se necesita especificar que columnas y de que tablas se seleccionarán:
 | |
| 
 | |
| ```php
 | |
| $query->select('id, name')
 | |
|     ->from('user');
 | |
| ```
 | |
| 
 | |
| Las opciones de select se pueden especificar como una cadena de texto (string) separada por comas o como un array. La
 | |
| sintaxis del array es especialmente útil cuando se forma la selección dinámicamente.
 | |
| 
 | |
| ```php
 | |
| $query->select(['id', 'name'])
 | |
|     ->from('user');
 | |
| ```
 | |
| 
 | |
| > Info: Se debe usar siempre el formato array si la clausula `SELECT` contiene expresiones SQL. Esto se debe a
 | |
|   que una expresión SQL como `CONCAT(first_name, last_name) AS full_name` puede contener comas. Si se junta con otra
 | |
|   cadena de texto de otra columna, puede ser que la expresión se divida en varias partes por comas, esto puede
 | |
|   conllevar a errores.
 | |
| 
 | |
| Cuando se especifican columnas, se pueden incluir los prefijos de las tablas o alias de columnas, ej.  `user.id`,
 | |
| `user.id AS user_id`. Si se usa un array para especificar las columnas, también se pueden usar las claves del array
 | |
| para especificar los alias de columna, ej. `['user_id' => 'user.id', 'user_name' => 'user.name']`.
 | |
| 
 | |
| A partir de la versión 2.0.1, también se pueden seleccionar subconsultas como columnas. Por ejemplo:
 | |
| 
 | |
| ```php
 | |
| $subQuery = (new Query)->select('COUNT(*)')->from('user');
 | |
| $query = (new Query)->select(['id', 'count' => $subQuery])->from('post');
 | |
| // $query representa la siguiente sentencia SQL:
 | |
| // SELECT `id`, (SELECT COUNT(*) FROM `user`) AS `count` FROM `post`
 | |
| ```
 | |
| 
 | |
| Para seleccionar filas distintas, se puede llamar a `distinct()`, como se muestra a continuación:
 | |
| 
 | |
| ```php
 | |
| $query->select('user_id')->distinct()->from('post');
 | |
| ```
 | |
| 
 | |
| ### `FROM`
 | |
| 
 | |
| Para especificar de que tabla(s) se quieren seleccionar los datos, se llama a `from()`:
 | |
| 
 | |
| ```php
 | |
| $query->select('*')->from('user');
 | |
| ```
 | |
| 
 | |
| Se pueden especificar múltiples tablas usando una cadena de texto separado por comas o un array. Los nombres de tablas
 | |
| pueden contener prefijos de esquema (ej. `'public.user'`) y/o alias de tablas (ej. `'user u'). El método
 | |
| entrecomillara automáticamente los nombres de tablas a menos que contengan algún paréntesis (que significa que se
 | |
| proporciona la tabla como una subconsulta o una expresión de BD). Por ejemplo:
 | |
| 
 | |
| ```php
 | |
| $query->select('u.*, p.*')->from(['user u', 'post p']);
 | |
| ```
 | |
| 
 | |
| Cuando se especifican las tablas como un array, también se pueden usar las claves de los arrays como alias de tablas
 | |
| (si una tabla no necesita alias, no se usa una clave en formato texto). Por ejemplo:
 | |
| 
 | |
| ```php
 | |
| $query->select('u.*, p.*')->from(['u' => 'user', 'p' => 'post']);
 | |
| ```
 | |
| 
 | |
| Se puede especificar una subconsulta usando un objeto `Query`. En este caso, la clave del array correspondiente se
 | |
| usará como alias para la subconsulta.
 | |
| 
 | |
| ```php
 | |
| $subQuery = (new Query())->select('id')->from('user')->where('status=1');
 | |
| $query->select('*')->from(['u' => $subQuery]);
 | |
| ```
 | |
| 
 | |
| ### `WHERE`
 | |
| 
 | |
| Habitualmente se seleccionan los datos basándose en ciertos criterios. El Constructor de Consultas tiene algunos
 | |
| métodos útiles para especificarlos, el más poderoso de estos es `where`, y se puede usar de múltiples formas.
 | |
| 
 | |
| La manera más simple para aplicar una condición es usar una cadena de texto:
 | |
| 
 | |
| ```php
 | |
| $query->where('status=:status', [':status' => $status]);
 | |
| ```
 | |
| 
 | |
| Cuando se usan cadenas de texto, hay que asegurarse que se unen los parámetros de la consulta, no crear una consulta
 | |
| mediante concatenación de cadenas de texto. El enfoque anterior es seguro, el que se muestra a continuación, no lo es:
 | |
| 
 | |
| ```php
 | |
| $query->where("status=$status"); // Peligroso!
 | |
| ```
 | |
| 
 | |
| En lugar de enlazar los valores de estado inmediatamente, se puede hacer usando `params` o `addParams`:
 | |
| 
 | |
| ```php
 | |
| $query->where('status=:status');
 | |
| $query->addParams([':status' => $status]);
 | |
| ```
 | |
| 
 | |
| Se pueden establecer múltiples condiciones en `where` usando el *formato hash*.
 | |
| 
 | |
| ```php
 | |
| $query->where([
 | |
|     'status' => 10,
 | |
|     'type' => 2,
 | |
|     'id' => [4, 8, 15, 16, 23, 42],
 | |
| ]);
 | |
| ```
 | |
| 
 | |
| El código generará la el siguiente SQL:
 | |
| 
 | |
| ```sql
 | |
| WHERE (`status` = 10) AND (`type` = 2) AND (`id` IN (4, 8, 15, 16, 23, 42))
 | |
| ```
 | |
| 
 | |
| El valor NULO es un valor especial en las bases de datos, y el Constructor de Consultas lo gestiona inteligentemente.
 | |
| Este código:
 | |
| 
 | |
| ```php
 | |
| $query->where(['status' => null]);
 | |
| ```
 | |
| 
 | |
| da como resultado la siguiente cláusula WHERE:
 | |
| 
 | |
| ```sql
 | |
| WHERE (`status` IS NULL)
 | |
| ```
 | |
| 
 | |
| También se pueden crear subconsultas con objetos de tipo `Query` como en el siguiente ejemplo:
 | |
| 
 | |
| ```php
 | |
| $userQuery = (new Query)->select('id')->from('user');
 | |
| $query->where(['id' => $userQuery]);
 | |
| ```
 | |
| 
 | |
| que generará el siguiente código SQL:
 | |
| 
 | |
| ```sql
 | |
| WHERE `id` IN (SELECT `id` FROM `user`)
 | |
| ```
 | |
| 
 | |
| Otra manera de usar el método es el formato de operando que es `[operator, operand1, operand2, ...]`.
 | |
| 
 | |
| El operando puede ser uno de los siguientes (ver también [[yii\db\QueryInterface::where()]]):
 | |
| 
 | |
| - `and`: los operandos deben concatenerase usando `AND`. por ejemplo, `['and', 'id=1', 'id=2']` generará
 | |
|   `id=1 AND id=2`. Si el operando es un array, se convertirá en una cadena de texto usando las reglas aquí descritas.
 | |
|   Por ejemplo, `['and', 'type=1', ['or', 'id=1', 'id=2']]` generará `type=1 AND (id=1 OR id=2)`. El método no
 | |
|   ejecutará ningún filtrado ni entrecomillado.
 | |
| 
 | |
| - `or`: similar al operando `and` exceptuando que los operando son concatenados usando `OR`.
 | |
| 
 | |
| - `between`: el operando 1 debe ser el nombre de columna, y los operandos 2 y 3 deben ser los valores iniciales y
 | |
|   finales del rango en el que se encuentra la columna. Por ejemplo, `['between', 'id', 1, 10]` generará
 | |
|   `id BETWEEN 1 AND 10`.
 | |
| 
 | |
| - `not between`: similar a `between` exceptuando que  `BETWEEN` se reemplaza por `NOT BETWEEN` en la condición
 | |
|   generada.
 | |
| 
 | |
| - `in`: el operando 1 debe ser una columna o una expresión de BD. El operando 2 puede ser un array o un objeto de tipo
 | |
|   `Query`. Generará una condición `IN`. Si el operando 2 es un array, representará el rango de valores que puede
 | |
|   albergar la columna o la expresión de BD; Si el operando 2 es un objeto de tipo `Query`, se generará una subconsulta
 | |
|   y se usará como rango de la columna o de la expresión de BD. Por ejemplo, `['in', 'id', [1, 2, 3]]` generará
 | |
|   `id IN (1, 2, 3)`. El método entrecomillará adecuadamente el nombre de columna y filtrará los valores del rango. El
 | |
|   operando `in` también soporta columnas compuestas. En este caso, el operando 1 debe se un array de columnas,
 | |
|   mientras que el operando 2 debe ser un array de arrays o un objeto de tipo `Query` que represente el rango de las
 | |
|   columnas.
 | |
| 
 | |
| - `not in`: similar que el operando `in` exceptuando que `IN` se reemplaza por `NOT IN` en la condición generada.
 | |
| 
 | |
| - `like`: el operando 1 debe ser una columna o una expresión de BD, y el operando 2 debe ser una cadena de texto o un
 | |
|   array que represente los valores a los que tienen que asemejarse la columna o la expresión de BD.Por ejemplo,
 | |
|   `['like', 'name', 'tester']` generará `name LIKE '%tester%'`. Cuando se da el valor rango como un array, se
 | |
|   generarán múltiples predicados `LIKE` y se concatenaran usando `AND`. Por ejemplo,
 | |
|   `['like', 'name', ['test', 'sample']]` generará `name LIKE '%test%' AND name LIKE '%sample%'`. También se puede
 | |
|   proporcionar un tercer operando opcional para especificar como deben filtrarse los caracteres especiales en los
 | |
|   valores. El operando debe se un array que mapeen los caracteres especiales a sus caracteres filtrados asociados. Si
 | |
|   no se proporciona este operando, se aplicará el mapeo de filtrado predeterminado. Se puede usar `false` o un array
 | |
|   vacío para indicar que los valores ya están filtrados y no se necesita aplicar ningún filtro. Hay que tener en
 | |
|   cuenta que cuando se usa un el mapeo de filtrado (o no se especifica el tercer operando), los valores se encerraran
 | |
|   automáticamente entre un par de caracteres de porcentaje.
 | |
| 
 | |
| > Note: Cuando se usa PostgreSQL también se puede usar
 | |
| [`ilike`](https://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE) en lugar de `like` para
 | |
| filtrar resultados insensibles a mayúsculas (case-insensitive).
 | |
| 
 | |
| - `or like`: similar al operando `like` exceptuando que se usa `OR` para concatenar los predicados `LIKE` cuando haya
 | |
|   un segundo operando en un array.
 | |
| 
 | |
| - `not like`: similar al operando `like` exceptuando que se usa `LIKE` en lugar de `NOT LIKE` en las condiciones
 | |
|   generadas.
 | |
| 
 | |
| - `or not like`: similar al operando `not like` exceptuando que se usa `OR` para concatenar los predicados `NOT LIKE`.
 | |
| 
 | |
| - `exists`: requiere un operando que debe ser una instancia de [[yii\db\Query]] que represente la subconsulta. Esto
 | |
|   generará una expresión `EXISTS (sub-query)`.
 | |
| 
 | |
| - `not exists`: similar al operando `exists` y genera una expresión `NOT EXISTS (sub-query)`.
 | |
| 
 | |
| Adicionalmente se puede especificar cualquier cosa como operando:
 | |
| 
 | |
| ```php
 | |
| $query->select('id')
 | |
|     ->from('user')
 | |
|     ->where(['>=', 'id', 10]);
 | |
| ```
 | |
| 
 | |
| Cuyo resultado será:
 | |
| 
 | |
| ```sql
 | |
| SELECT id FROM user WHERE id >= 10;
 | |
| ```
 | |
| 
 | |
| Si se construyen partes de una condición dinámicamente, es muy convenientes usar `andWhere()` y `orWhere()`:
 | |
| 
 | |
| ```php
 | |
| $status = 10;
 | |
| $search = 'yii';
 | |
| 
 | |
| $query->where(['status' => $status]);
 | |
| if (!empty($search)) {
 | |
|     $query->andWhere(['like', 'title', $search]);
 | |
| }
 | |
| ```
 | |
| 
 | |
| En el caso que `$search` no este vacío, se generará el siguiente código SQL:
 | |
| 
 | |
| ```sql
 | |
| WHERE (`status` = 10) AND (`title` LIKE '%yii%')
 | |
| ```
 | |
| 
 | |
| #### Construcción de Condiciones de Filtro
 | |
| 
 | |
| Cuando se generan condiciones de filtro basadas en datos recibidos de usuarios (inputs), a menudo se quieren gestionar
 | |
| de forma especial las "datos vacíos" para ignorarlos en los filtros. Por ejemplo, teniendo un formulario HTML que
 | |
| obtiene el nombre de usuario y la dirección de correo electrónico. Si el usuario solo rellena el campo de nombre de
 | |
| usuario, se puede querer generar una consulta para saber si el nombre de usuario recibido es valido. Se puede usar
 | |
| `filterWhere()` para conseguirlo:
 | |
| 
 | |
| ```php
 | |
| // $username y $email son campos de formulario rellenados por usuarios
 | |
| $query->filterWhere([
 | |
|     'username' => $username,
 | |
|     'email' => $email,
 | |
| ]);
 | |
| ```
 | |
| 
 | |
| El método `filterWhere()` es muy similar al método `where()`. La principal diferencia es que el `filterWhere()`
 | |
| eliminará los valores vacíos de las condiciones proporcionadas. Por lo tanto si `$email` es "vació", la consulta
 | |
| resultante será `...WHERE username=:username`; y si tanto `$username` como `$email` son "vacías", la consulta no
 | |
| tendrá `WHERE`.
 | |
| 
 | |
| Decimos que un valor es *vacío* si es nulo, una cadena de texto vacía, una cadena de texto que consista en espacios en
 | |
| blanco o un array vacío.
 | |
| 
 | |
| También se pueden usar `andFilterWhere()` y `orFilterWhere()` para añadir más condiciones de filtro.
 | |
| 
 | |
| ### `ORDER BY`
 | |
| 
 | |
| Se pueden usar `orderBy` y `addOrderBy` para ordenar resultados:
 | |
| 
 | |
| ```php
 | |
| $query->orderBy([
 | |
|     'id' => SORT_ASC,
 | |
|     'name' => SORT_DESC,
 | |
| ]);
 | |
| ```
 | |
| 
 | |
| Aquí estamos ordenando por `id` ascendente y después por `name` descendente.
 | |
| 
 | |
| ### `GROUP BY` and `HAVING`
 | |
| 
 | |
| Para añadir `GROUP BY` al SQL generado se puede usar el siguiente código:
 | |
| 
 | |
| ```php
 | |
| $query->groupBy('id, status');
 | |
| ```
 | |
| 
 | |
| Si se quieren añadir otro campo después de usar `groupBy`:
 | |
| 
 | |
| ```php
 | |
| $query->addGroupBy(['created_at', 'updated_at']);
 | |
| ```
 | |
| 
 | |
| Para añadir la condición `HAVING` se pueden usar los métodos `having` y `andHaving` y `orHaving`. Los parámetros para
 | |
| ellos son similares a los del grupo de métodos `where`:
 | |
| 
 | |
| ```php
 | |
| $query->having(['status' => $status]);
 | |
| ```
 | |
| 
 | |
| ### `LIMIT` and `OFFSET`
 | |
| 
 | |
| Para limitar el resultado a 10 filas se puede usar `limit`:
 | |
| 
 | |
| ```php
 | |
| $query->limit(10);
 | |
| ```
 | |
| 
 | |
| Para saltarse las 100 primeras filas, se puede usar:
 | |
| 
 | |
| ```php
 | |
| $query->offset(100);
 | |
| ```
 | |
| 
 | |
| ### `JOIN`
 | |
| 
 | |
| Las clausulas `JOIN` se generan en el Constructor de Consultas usando el método join aplicable:
 | |
| 
 | |
| - `innerJoin()`
 | |
| - `leftJoin()`
 | |
| - `rightJoin()`
 | |
| 
 | |
| Este left join selecciona los datos desde dos tablas relacionadas en una consulta:
 | |
| 
 | |
| ```php
 | |
| $query->select(['user.name AS author', 'post.title as title'])
 | |
|     ->from('user')
 | |
|     ->leftJoin('post', 'post.user_id = user.id');
 | |
| ```
 | |
| 
 | |
| En el código, el primer parámetro del método `leftjoin` especifica la tabla a la que aplicar el join. El segundo
 | |
| parámetro, define la condición del join.
 | |
| 
 | |
| Si la aplicación de bases de datos soporta otros tipos de joins, se pueden usar mediante el método `join` genérico:
 | |
| 
 | |
| ```php
 | |
| $query->join('FULL OUTER JOIN', 'post', 'post.user_id = user.id');
 | |
| ```
 | |
| 
 | |
| El primer argumento es el tipo de join a realizar. El segundo es la tabla a la que aplicar el join, y el tercero es la condición:
 | |
| 
 | |
| Como en `FROM`, también se pueden efectuar joins con subconsultas. Para hacerlo, se debe especificar la subconsulta
 | |
| como un array que tiene que contener un elemento. El valor del array tiene que ser un objeto de tipo `Query` que
 | |
| represente la subconsulta, mientras que la clave del array es el alias de la subconsulta. Por ejemplo:
 | |
| 
 | |
| ```php
 | |
| $query->leftJoin(['u' => $subQuery], 'u.id=author_id');
 | |
| ```
 | |
| 
 | |
| ### `UNION`
 | |
| 
 | |
| En SQL `UNION` agrega resultados de una consulta a otra consulta. Las columnas devueltas por ambas consultas deben
 | |
| coincidir. En Yii para construirla, primero se pueden formar dos objetos de tipo query y después usar el método
 | |
| `union`:
 | |
| 
 | |
| ```php
 | |
| $query = new Query();
 | |
| $query->select("id, category_id as type, name")->from('post')->limit(10);
 | |
| 
 | |
| $anotherQuery = new Query();
 | |
| $anotherQuery->select('id, type, name')->from('user')->limit(10);
 | |
| 
 | |
| $query->union($anotherQuery);
 | |
| ```
 | |
| 
 | |
| Consulta por Lotes
 | |
| ---------------
 | |
| 
 | |
| Cuando se trabaja con grandes cantidades de datos, los métodos como [[yii\db\Query::all()]] no son adecuados ya que
 | |
| requieren la carga de todos los datos en memoria. Para mantener los requerimientos de memoria reducidos, Yii
 | |
| proporciona soporte a las llamadas consultas por lotes (batch query). Una consulta por lotes usa un cursor de datos y
 | |
| recupera los datos en bloques.
 | |
| 
 | |
| Las consultas por lotes se pueden usar del siguiente modo:
 | |
| 
 | |
| ```php
 | |
| use yii\db\Query;
 | |
| 
 | |
| $query = (new Query())
 | |
|     ->from('user')
 | |
|     ->orderBy('id');
 | |
| 
 | |
| foreach ($query->batch() as $users) {
 | |
|     // $users is an array of 100 or fewer rows from the user table
 | |
| }
 | |
| 
 | |
| // o si se quieren iterar las filas una a una
 | |
| foreach ($query->each() as $user) {
 | |
|     // $user representa uno fila de datos de la tabla user
 | |
| }
 | |
| ```
 | |
| 
 | |
| Los métodos [[yii\db\Query::batch()]] y [[yii\db\Query::each()]] devuelven un objeto [[yii\db\BatchQueryResult]] que
 | |
| implementa una interfaz `Iterator` y así se puede usar en el constructor `foreach`. Durante la primera iteración, se
 | |
| efectúa una consulta SQL a la base de datos. Desde entonces, los datos se recuperan por lotes en las iteraciones. El
 | |
| tamaño predeterminado de los lotes es 100, que significa que se recuperan 100 filas de datos en cada lote. Se puede
 | |
| modificar el tamaño de los lotes pasando pasando un primer parámetro a los métodos `batch()` o `each()`.
 | |
| 
 | |
| En comparación con [[yii\db\Query::all()]], las consultas por lotes sólo cargan 100 filas de datos en memoria cada
 | |
| vez. Si el procesan los datos y después se descartan inmediatamente, las consultas por lotes, pueden ayudar a mantener
 | |
| el uso de memora bajo un limite.
 | |
| 
 | |
| Si se especifica que el resultado de la consulta tiene que ser indexado por alguna columna mediante
 | |
| [[yii\db\Query::indexBy()]], las consultas por lotes seguirán manteniendo el indice adecuado. Por ejemplo,
 | |
| 
 | |
| ```php
 | |
| use yii\db\Query;
 | |
| 
 | |
| $query = (new Query())
 | |
|     ->from('user')
 | |
|     ->indexBy('username');
 | |
| 
 | |
| foreach ($query->batch() as $users) {
 | |
|     // $users esta indexado en la columna "username"
 | |
| }
 | |
| 
 | |
| foreach ($query->each() as $username => $user) {
 | |
| }
 | |
| ```
 | 
