Actualizar una colección de Eloquent en Laravel en una sola query

Veamos cómo usar el método toQuery para actualizar múltiples registros desde una colección de Eloquent.

Actualizar una colección de Eloquent en Laravel en una sola query
Photo by Caspar Camille Rubin / Unsplash

Cuando usamos Eloquent, muchas veces necesitamos actualizar múltiples modelos que ya tenemos cargados en memoria. Si intentamos ejecutar lo siguiente:

$products = Product::active()->get();
// ...
$products->update([
	'is_active' => false,
]);

Nos devolverá un error ya que el resultado del →get() es una colección, y las colecciones no tienen un método update().

En muchos tutoriales y preguntas de Stack Overflow veremos que nos recomiendan lo siguiente:

$products = Product::active()->get();
// ...
$products->each->update([
	'is_active' => false,
]);

Sin embargo, esta solución ejecutará N queries, por lo que si estás actualizando 1.000 productos ejecutará 1.000 queries diferentes.

Ejecutando el update con un where()

Una de las opciones que tenemos para reducir las N queries a 1 única query es la de obtener los IDs de cada modelo, y hacer el update manual:

$products = Product::active()->get();
// ...
$ids = $products->pluck('id');
Product::whereIn('id', $ids)->update([
	'is_active' => false,
]);

Este código nos reduciría las N queries del update a una sola query, actualizando todos los registros de un plumazo. Sin embargo, hay otra forma un poco más corta y que no requiere jugar con los métodos de las colecciones.

Actualizando múltiples registros usando toQuery()

Al ser esto tan común, Eloquent ya nos viene con una implementación de este algoritmo por defecto a través del método toQuery(). Para usarlo:

$products = Product::active()->get();
// ...
$products->toQuery()->update([
	'is_active' => false,
]);