【发布时间】:2020-07-16 10:55:29
【问题描述】:
我不是 Eloquent 大师,我做了很多研究,但无法重现我的预期。
我有以下型号:
<?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);
}
}
当我搜索特定的Invoice::class:
$invoice = Invoice::number($number)
->latest('started_at')
->with(['contacts'])
->firstOrFail();
我需要这样退回:
{
"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"
}
我目前正在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');
但是数据量非常大,我想删除EagerLoading并在单个查询中完成所有操作以减少对数据库的影响。
关于如何仅使用Eloquent 解决此问题的任何想法?
更新
一位朋友帮我解决了我想转换为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
【问题讨论】:
-
如果我正确理解了您的问题,那么您不应该删除
EagerLoading,因为它目前可以为您节省大量查询。我认为你现在应该只有两个:一个给你发票,一个给你发票的联系人。执行$this->contacts->sum('incoming_messages');不会进行额外的查询。 -
@thefallen 问题是:在某些时候,每张发票可以有超过 100,000 个联系人。据我所知
EagerLoading将返回给我所有的联系人数据,最后我只需要指定列的总和。 Mysql 可以在不返回所有联系人的情况下求和,这会为我节省一些资源... -
这是一个利用withCount() 方法的“hack”:laravel-eloquent-query-with-sum-of-related-table。但我个人更愿意使用
Invoice::hydrateRaw('<your_raw_query>', <bindings>)。