Aquí se hizo una pregunta similar.
Estoy trabajando en las API. Mi tabla de productos contiene más de diez mil productos de diferentes categorías. Necesito disminuir el tiempo de ejecución de la consulta, por lo que, para ese propósito, debo modificar una API que obtendrá solo 20 productos de cada categoría y agrupará toda la respuesta de la API por categoría. La respuesta de la API será como la siguiente.
{ "data": { "products": { "Beauticians & Style": [ { "Title": "Product A", "Price": "0.00", "DiscountPrice": 0 }, { "Title": "Product B", "Price": "0.00", "DiscountPrice": 0 } ], "Groceries": [ { "Title": "Product G", "Price": "0.00", "DiscountPrice": 0 }, { "Title": "Product R", "Price": "0.00", "DiscountPrice": 0 }, { "Title": "Product O", "Price": "0.00", "DiscountPrice": 0 }, { "Title": "Product C", "Price": "0.00", "DiscountPrice": 0 } ], "Women's Fashion": [ { "Title": "Product W", "Price": "0.00", "DiscountPrice": 0 }, { "Title": "Product O", "Price": "0.00", "DiscountPrice": 0 }, { "Title": "Product M", "Price": "0.00", "DiscountPrice": 0 } ] } }Controlador
$products = Category::with('products', function($q){ $q->take(20); })->get();Categoría Modelo
class Category extends Model { use HasFactory; public function products() { return $this->hasMany('App\Models\Product', 'CategoryID', 'CategoryID'); } }Intenté esto pero no obtuve el resultado exacto.
Al acceder a las relaciones de Eloquent como propiedades, los modelos relacionados se "cargan de forma diferida" . Esto significa que los datos de la relación no se cargan realmente hasta que accede por primera vez a la propiedad.
La solución, puedes usar:
$products = Category::with('products') ->get() ->map(function ($query) { $query->setRelation('products', $query->products->take(20)); return $query; });Referencia:
OP comentario:
Pero en este caso, buscamos todos los productos de 10k y luego establecemos la relación en la colección.
Sí, este es un problema de rendimiento, pero su pregunta es sobre eadger. Esta es la limitación .
Elocuente como herramienta, no como solución. Es solo un contenedor en SQL. Si desea limitar el número de productos por categoría a (n) , la consulta se vuelve compleja.
Para resolver este problema, necesitará usar la función de ventana :
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY `category_id`) AS row_num FROM `products` ) AS temp_table WHERE row_num <= 10 ORDER BY row_numAlternativamente, puede usar esta extensión Laravel Eloquent para permitir limitar la cantidad de resultados de carga ansiosos por padre usando funciones de ventana.
Categoría Modelo
use Staudenmeir\EloquentEagerLimit\HasEagerLimit; use App\Models\Product; class Category extends Model { use HasEagerLimit; public function products() { return $this->hasMany(Product::class); } }Modelo del Producto
use Staudenmeir\EloquentEagerLimit\HasEagerLimit; class Product extends Model { use HasEagerLimit; }Probar
$products = Category::with(['products' => function ($query) { $query->latest()->limit(20); }])->get();¿Te explica esto lo suficiente?
si cada producto tiene solo una categoría, la estructura de sus tablas debe ser la siguiente:
products id ... category_id categories id ...y la relación de sus productos en Categoría debe ser la siguiente:
class Category extends Model { use HasFactory; public function products() { return $this->hasMany(App\Models\Product::class); } }y cambie su controlador a:
$products = Category::with('products', function($q){ $q->take(20); })->get();