Laravel - Eloquent - 根据最新的HasMany关系过滤

时间:2018-05-07 16:36:05

标签: mysql laravel eloquent

我有两个模型,即潜在客户和状态。

class Lead extends Model
{
    public function statuses() {
        return $this->hasMany('App\LeadStatus', 'lead_id', 'id')
            ->orderBy('created_at', 'DESC');
    }

    public function activeStatus() {
        return $this->hasOne('App\LeadStatus', 'lead_id', 'id')
            ->latest();
    }


}

class LeadStatus extends Model
{
    protected $fillable = ['status', 'lead_id'];
}

这很好用,现在我试图根据最后一个LeadStatus的'status'来获取所有潜在客户。

我尝试了几种组合但没有成功。

if ($search['status']) {
            $builder = $builder
                ->whereHas('statuses', function($q) use ($search){
                    $q = $q->latest()->limit(1);
                    $q->where('status', $search['status']);
                });
        }



 if ($search['status']) {
            $builder = $builder
                ->whereHas('status', function($q) use ($search){
                    $q = $q->latest()->Where('status', $search['status']);
                });
        }

有没有人用Eloquent做过这件事?我是否需要编写一些原始SQL查询?

编辑1:我会再次尝试解释:D

在我的数据库中,潜在客户的状态不是1对1的关系。那是因为我希望得到一个Lead所拥有的所有状态的历史列表。

这意味着当创建潜在客户时,将创建第一个LeadStatus,其状态为“new”和当前日期。

如果推销员进来,他可以更改潜在客户的状态,但这不会更新以前的LeadStatus,而是创建一个新的相关LeadStatus,其当前日期和状态为“打开”。

通过这种方式,我可以看到在05/05/2018创建了一个潜在客户,并且它已于07/05/2018更改为“已打开”状态。

现在我正在尝试使用eloquent编写查询,只需要计算与潜在客户相关的最新状态。

在上一个示例中,如果我使用状态为“new”的Lead进行过滤,则此Lead应该不会显示,因为它现在处于“打开”状态。

希望这有帮助

3 个答案:

答案 0 :(得分:1)

试试这个:

Lead::select('leads.*')
    ->join('lead_statuses', 'leads.id', 'lead_statuses.lead_id')
    ->where('lead_statuses.status', $search['status'])
    ->where('created_at', function($query) {
        $query->selectRaw('max(created_at)')
            ->from('lead_statuses')
            ->whereColumn('lead_id', 'leads.id');
    })->get();

使用主键(Borjante)的解决方案:

    $builder->where('lead_statuses.id', function($query) {
        $query->select('id')
            ->from('lead_statuses')
            ->whereColumn('lead_id', 'leads.id')
            ->orderBy('created_at', 'desc')
            ->limit(1);
    });

答案 1 :(得分:0)

如果我理解正确,您需要/想要让所有潜在客户获得特定状态。

所以你可能应该这样做:

    // In your Modal

    public function getLeadById($statusId)
    {
        return Lead::where('status', $statusId)->get();
        // you could of course extend this and do something like this:
        // return Lead::where('status', $statusId)->limit()....->get();
    }

基本上我正在做一个地方,并返回具有特定身份的每个潜在客户。

然后您可以在控制器中使用此功能,如下所示:

Lead::getLeadById(1)

答案 2 :(得分:0)

我也遇到了同样的问题,并发布了my solution here,但我认为值得重新发布,因为它提高了可重用性。这个想法与接受的答案相同,但是避免使用联接,如果您希望加载关系或在范围内使用它,可能会导致问题。

第一步是将宏添加到Builder中的查询AppServiceProvider

use Illuminate\Database\Query\Builder;

Builder::macro('whereLatestRelation', function ($table, $parentRelatedColumn) 
{
    return $this->where($table . '.id', function ($sub) use ($table, $parentRelatedColumn) {
        $sub->select('id')
            ->from($table . ' AS other')
            ->whereColumn('other.' . $parentRelatedColumn, $table . '.' . $parentRelatedColumn)
            ->latest()
            ->take(1);
    });
});

这基本上使子查询的接受答案更为通用,从而允许您指定联接表和它们联接的列。它还使用latest()函数来避免直接引用created_at列。假设另一列是“ id”列,则可以对其进行进一步改进。要使用此功能,您就可以做到:

$status = $search['status'];
Lead::whereHas('statuses', function ($q) use ($status) {
    $q->where('status', $userId)
        ->whereLatestRelation((new LeadStatus)->getTable(), 'lead_id');
});

与接受的答案逻辑相同,但重用起来更容易。但是,它会慢一些,但是值得重复使用。