> Faqs > Traer la cuenta de elementos relacionados con eager loading en Laravel Eloquent

Traer la cuenta de elementos relacionados con eager loading en Laravel Eloquent

Tengo una pregunta relacionada con el sistema de eager loading en Laravel.

En Laravel, cuando hago una consulta con Eloquent, por ejemplo me puedo traer una relación completa con el with().

Customer::with(['invoices', 'quotes'])->get();

Pero quiero un caso especial y es que de los "quotes" solamente quiero traerme el número de elementos que tengo, no los elementos en si. ¿Esto como se hace de manera optimizada con el eager loading? y luego ¿cómo accedo a esa cuenta de elementos quote?

Y otra situación un poco más compleja. Pongamos que me quiero traer la cuenta del número de productos que tiene una factura ¿cómo lo haría estando consultando en Customer?,

Sabiendo que hay una relación así:

  • Customer
    • quotes
    • invoices
      • products (invoices tiene una relacion de products)

Respuestas

Para lograr lo que deseas, puedes usar el método withCount en lugar de with. Esto te permitirá obtener el número de elementos relacionados sin cargar los propios elementos. Este método es especialmente útil cuando solo necesitas contar los elementos relacionados y no trabajar directamente con ellos (evitas cargar datos innecesarios).

Aquí tienes un ejemplo de cómo podrías hacerlo:

$customers = Customer::withCount('quotes')->get();

Esto agregará una propiedad quotes_count a cada modelo Customer en la colección resultante, la cual contiene el número de quotes relacionados con cada Customer.

Luego, puedes acceder a esta cuenta de elementos de quotes para un cliente específico de la siguiente manera:

foreach ($customers as $customer) {
    echo $customer->quotes_count;
}

Cada Customer en la colección tendrá una propiedad quotes_count que puedes utilizar para mostrar el número de quotes relacionados.

Si deseas cargar también otra relación completa como invoices mientras usas withCount para quotes, puedes hacerlo así:

$customers = Customer::with('invoices')->withCount('quotes')->get();

De esta manera, estarás cargando todas las facturas relacionadas con cada cliente y, al mismo tiempo, contando el número de quotes para cada uno, todo en una operación optimizada de eager loading.

eager loading de la cuenta de la relación eloquent a un segundo nivel

El segundo caso que comentas puede ser un poco más complejo, porque withCount no permite acceder a la cuenta de las relaciones de relaciones... no sé si me explico.

Entonces, para obtener la cuenta del número de productos en cada factura mientras cargas las facturas asociadas a cada cliente, puedes utilizar la función with para cargar las facturas y la función withCount para contar los productos en cada factura. Sin embargo, dado que deseas contar los productos dentro de una relación anidada (facturas de un cliente), necesitas hacer un poco más de trabajo para especificar correctamente la relación anidada.

Puedes lograr esto utilizando el método with y pasando una función de callback para especificar la relación anidada y aplicar withCount a esa relación anidada. Aquí te muestro cómo podrías hacerlo:

$customers = Customer::with(['invoices' => function ($query) {
    $query->withCount('products');
}])->get();

En este código, estamos cargando todos los clientes y, para cada cliente, cargamos sus facturas. Para cada factura, en lugar de cargar todos los productos asociados, estamos contando el número de productos y este conteo se agregará a cada modelo de factura como una propiedad products_count.

Luego, puedes acceder a la cuenta de productos para cada factura de un cliente específico de la siguiente manera:

foreach ($customers as $customer) {
    foreach ($customer->invoices as $invoice) {
        echo $invoice->products_count;
    }
}

Cada Invoice en la colección de facturas de cada Customer tendrá una propiedad products_count que puedes utilizar para mostrar el número de productos asociados con esa factura.

Espero haberte contestado bien, sin haber probado los ejemplos, ya me dirás si te funciona todo correctamente.

Julian
1100 46 84 45