El problema oculto detrás de las validaciones masivas
Cuando validamos arrays de datos en Laravel usando reglas como unique, el framework realiza una consulta por cada elemento del array.
Por ejemplo, si validas una lista de correos electrónicos con la regla unique:users,email, Laravel ejecutará una consulta por cada email.
Esto genera lo que conocemos como el problema N+1, un clásico enemigo del rendimiento en bases de datos.
¿Qué es el problema N+1 en validaciones?
El problema ocurre así:
- Tienes un array con N elementos.
- Laravel ejecuta N consultas SQL para validar cada uno.
- A medida que el tamaño del array crece, también lo hace el número de consultas.
Esto puede pasar desapercibido en pequeños formularios, pero en procesos masivos (importaciones, APIs, migraciones de datos) se convierte en un cuello de botella enorme.
Solución
Validaciones por lotes con laravel-batch-validation
dazza-dev/laravel-batch-validation soluciona este problema optimizando el flujo de validación de Laravel.
En lugar de validar cada elemento de forma individual, tu paquete agrupa las validaciones y ejecuta una sola consulta WHERE IN por lote.
De esta forma:
- Reduces cientos de consultas a solo una o unas pocas.
- Mantienes la sintaxis y el sistema de validación nativo de Laravel.
- Mejoras radicalmente el rendimiento sin complicaciones adicionales.
Instalación
composer require dazza-dev/laravel-batch-validation
Laravel detectará automáticamente el paquete gracias al auto-discovery, así que no es necesario registrar nada manualmente.
Validando arrays sin N+1
Imagina que recibes un array con varios contactos a validar:
use Illuminate\Support\Facades\Validator;
$data = [
['name' => 'User 1', 'email' => 'user1@example.com'],
['name' => 'User 2', 'email' => 'user2@example.com'],
['name' => 'User 3', 'email' => 'user3@example.com'],
];
// Crear una instancia del validador
$validator = Validator::make($data, [
'*.name' => 'required',
'*.email' => 'email:strict|unique:contacts,email',
]);
// Validar por lotes (evita el problema N+1)
$validator->validateInBatches();
// Si hay errores de validación
if ($validator->fails()) {
throw new \Exception(json_encode($validator->errors()->messages()));
}
Con este enfoque, en lugar de ejecutar una consulta por cada email, el paquete agrupa todos los valores y ejecuta una sola consulta con WHERE IN.
Controla el tamaño del lote
En algunos escenarios puede ser útil definir el tamaño del lote para balancear carga y consumo de memoria.
Esto lo haces fácilmente pasando el parámetro batchSize al método validateInBatches:
$validator->validateInBatches(batchSize: 20);
Esto significa que el validador procesará los datos en grupos de 20 registros a la vez. Ideal para validaciones sobre conjuntos muy grandes de datos.
Integración con FormRequests
El paquete también funciona perfectamente con las clases FormRequest de Laravel, manteniendo una integración limpia y natural.
Por ejemplo:
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Validator;
class StoreContactRequest extends FormRequest
{
public function rules(): array
{
return [
'*.name' => 'required',
'*.email' => 'email:strict|unique:contacts,email',
];
}
public function withValidator(Validator $validator)
{
if (method_exists($validator, 'validateInBatches')) {
$validator->validateInBatches(batchSize: 100);
}
}
}
De esta manera, tus validaciones en FormRequest también se ejecutan en lotes, sin alterar las reglas ni la lógica de tu aplicación.
Resultado
Conclusión
dazza-dev/laravel-batch-validation una optimización elegante y transparente para proyectos Laravel que necesitan validar grandes cantidades de datos.
Menos consultas. Más velocidad. Misma sintaxis Laravel.
Una herramienta imprescindible si trabajas con importaciones, APIs masivas o validaciones en bucles grandes.


Top comments (0)