Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

1.1K
Visualizações
Laravel Eloquent - Suma múltiples columnas de relaciones

No soy un maestro Eloquent , investigué mucho y no pude reproducir lo que esperaba.

Tengo los siguientes modelos:

 <?php use Illuminate\Database\Eloquent\Model; class Invoice extends Model { protected $fillable = [ 'uuid', 'number_id' ]; protected $dates = [ 'started_at', 'ended_at' ]; public $timestamps = false; public function contacts() { return $this->hasMany(Contact::class); } }
 <?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Contact extends Model { protected $fillable = [ 'incoming_messages', 'outgoing_messages', 'outgoing_template_messages', ]; public $timestamps = false; public function invoice() { return $this->belongsTo(Invoice::class); } }

Cuando busco una Invoice::class específica:

 $invoice = Invoice::number($number) ->latest('started_at') ->with(['contacts']) ->firstOrFail();

Necesito que me lo devuelvan así:

 { "id": 1, "number_id": "444a13fd-9789-426e-bdfb-c3e2e83c4422", "incoming_messages": 10, #(sum of invoice.contacts.incoming_messages) "outgoing_messages": 10, #(sum of invoice.contacts.outgoing_messages) "outgoing_template_messages": 10, #(sum of invoice.contacts.outgoing_template_messages) "started_at": "2020-07-01T00:00:00.000000Z", "ended_at": "2020-07-31T23:59:59.000000Z" }

Actualmente estoy haciendo esto dentro de InvoiceResource::class :

 $incoming_messages = $this->contacts->sum('incoming_messages'); $outgoing_messages = $this->contacts->sum('outgoing_messages'); $outgoing_template_messages = $this->contacts->sum('outgoing_template_messages');

Sin embargo, el volumen de datos es muy grande y me gustaría eliminar EagerLoading y hacer todo en una sola consulta para disminuir el impacto en la base de datos.

¿Alguna idea sobre cómo resolver este problema usando solo Eloquent ?


Actualizar

Un amigo me ayudó con la consulta que me gustaría convertir a Eloquent :

 SELECT a.number_id , sum(incoming_messages) as 'incoming_messages' , sum(outgoing_messages) as 'outgoing_messages' , sum(outgoing_template_messages) as 'outgoing_template_messages' , a.started_at , a.ended_at FROM invoices a inner join contacts b on a.id = b.invoice_id Where number_id = '45bh1h2g14h214hg2' Group By a.started_at , a.ended_at
over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Logré hacer la consulta usando solo elocuente. El rendimiento de mi base de datos ha cambiado drásticamente como se esperaba.

Esta es la consulta usando solo elocuente:

 $invoice = Invoice::number($number) ->selectRaw('invoices.uuid as uuid, invoices.number_id as number_id, count(*) as contacts, sum(incoming_messages) as incoming_messages, sum(outgoing_messages) as outgoing_messages, sum(outgoing_template_messages) as outgoing_template_messages, invoices.started_at, invoices.ended_at') ->join('contacts', 'contacts.invoice_id', '=', 'invoices.id') ->groupBy('invoices.id') ->latest('started_at') ->firstOrFail();

Actualizar

Tuve un problema donde mi consulta no devolvía facturas que no tenían ningún contacto, tuve que hacer un pequeño cambio.

El método join() genera una inner join , la inner join no incluye filas de table A que no tienen elementos en table B

Para superar esta situación, left join . Sin embargo, si la left join no tiene valores en table B , estaba devolviendo mis sumas como null .

Para resolver esto, simplemente usé la función ifnull() .

Esta es la consulta final:

 $invoices = Invoice::number($number) ->selectRaw('invoices.uuid as uuid, invoices.number_id as number_id, ifnull(count(contacts.id), 0) as contacts, ifnull(sum(incoming_messages), 0) as incoming_messages, ifnull(sum(outgoing_messages), 0) as outgoing_messages, ifnull(sum(outgoing_template_messages), 0) as outgoing_template_messages, invoices.started_at, invoices.ended_at') ->leftJoin('contacts', 'contacts.invoice_id', '=', 'invoices.id') ->groupBy('invoices.id') ->firstOrFail();
over 4 years ago · Santiago Trujillo Relatório

0

Podrías intentar algo como:

 $incoming_messages = $this->contacts() ->selectRaw('SUM(incoming_messages) as incoming_messages, SUM(outgoing_messages) as outgoing_messages, SUM(outgoing_template_messages) as outgoing_template_messages') ->get();

Es posible que pueda integrar esto en su consulta original de la siguiente manera:

 $invoice = Invoice::number($number) ->latest('started_at') ->with(['contacts' => function ($q) { $q->selectRaw('SUM(incoming_messages) as incoming_messages, SUM(outgoing_messages) as outgoing_messages, SUM(outgoing_template_messages) as outgoing_template_messages'); }]) ->firstOrFail();

Luego, accedería a los valores como $invoice->contacts->incoming_messages etc. Para que esto funcione al seleccionar más de una factura, es posible que deba agregar groupBy('invoice_id') si Factura-contactos es una relación de 1 a muchos (es decir, solo hay una factura para un contacto) si son muchos, es posible que necesite unirse a la tabla dinámica.

over 4 years ago · Santiago Trujillo Relatório

0

También puedes intentar usar un mutador para esto: https://laravel.com/docs/7.x/eloquent-mutators#defining-a-mutator

 public function incomingMessages() { return $this->contacts->sum('incoming_messages'); }

Y en su Recurso simplemente llamará:

 $this->incomingMessages()
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda