【问题标题】:Eloquent Filter by relationship (ONLY last record)Eloquent 按关系过滤(仅最后一条记录)
【发布时间】:2020-01-25 19:24:02
【问题描述】:

我将我的问题编辑得更明确

我需要建立一个过滤 hasMany 关系的范围。问题是,我想将该查询应用于 lastONLY,我的意思是,我希望我的模型由 HasMany 关系的特定记录的列过滤,是有可能吗?

上下文:一个有帖子的应用程序,每个帖子都有许多状态来保持历史。我想按每个帖子的最后状态过滤帖子。

帖子:

{
    public function statuses() 
    {
        return $this->hasMany(Status::class); // Only last one is important for querying
    }
}

然后,在一个范围内,我想做这样的事情:

public function scopeIsActive(Builder $builder)
{
    return $builder->whereHas('statuses', function(Builder $q) {
        // How to apply this ONLY to last created record???
        return $q->whereDate('activation', '<=', today());
    });
}

仅此而已!

编辑:(已解决的查询)

经过一番挖掘,我解决了这个问题:

public function scopeIsActive(Builder $builder)
{
    return $builder->whereHas('statuses', function (Builder $q) {
        return $q->whereDate('activation', '<=', today()) // applies to all
            ->where('statuses.id', function ($sub) { // applies to specific one
            return $sub->select('id')
                ->from('statuses')
                ->whereColumn('post_id', 'statuses.id')
                ->latest()
                ->limit(1);
        });
    });
}

【问题讨论】:

    标签: mysql laravel eloquent relationship has-many


    【解决方案1】:

    而不是

    public function others() 
    {
        return $this->hasMany(Other::class); // Only last one is important for querying
    }
    

    你可以这样做:

    
    public function other() 
    {
        return $this->hasOne(Other::class)->latest();
    }
    

    然后

    public function scopeCurrentActive(Builder $builder)
    {
        return $builder->whereHas('other', function(Builder $q) {
            return $q->whereDate('activation', '<=', today());
        });
    }
    

    但是你不能自定义订单,如果你想自定义订单,你必须使用子查询:

    return Model::orderByDesc(
        Other::select('arrived_at')
            ->whereColumn('model_id', 'model.id')
            ->orderBy('activation', 'desc')
            ->limit(1)
    )->get();
    

    如果想详细了解子查询,可以参考:

    https://laravel-news.com/eloquent-subquery-enhancements

    对于仅使用最后一条记录,您可能必须使用像这样的 having 语句,但我不确定确切的合成器 ^^

    
    public function scopeIsActive(Builder $builder)
    {
        return $builder->whereHas('statuses', function (Builder $q) {
            return $q->havingRaw(Other::select('arrived_at')
            ->whereColumn('model_id', 'model.id')
            ->orderBy('activation', 'desc')
            ->limit(1)->select('activation')->toSql(), '<=' , today());
        });
    }
    

    【讨论】:

    • 嗨,对不起,我认为它可以工作,但我意识到不是,HasOne() 关系产生与HasMany() 完全相同的 sql...所以,它不会让 LAST 记录过滤,它将考虑所有相关记录,而不仅仅是最后一个:(
    • 我更新了我的问题。我无法按最后一条记录过滤 T_T 看起来limit(1) 没有生效。我不确定生成的 SQL 语句是否正确或什么
    • 这是因为查询后限制是“应用”,我认为你应该使用have()语句,我会更新我的答案,但我不确定确切的合成器^^
    • 是的!问题出在查询位置!我可以解决这个问题并编辑我的问题。我还没有测试你的解决方案,但它可能也会起作用。谢谢你的帮助!!
    【解决方案2】:

    不确定您对每条记录的最后一条记录的确切含义

    您可以通过以下方式获取与最新帖子具有相同状态的所有帖子:

    public function scopeIsActive(Builder $builder)
    {
        $lastPostStatus = Post::select('status')
            ->orderBy('activation', 'desc')
            ->first()
            ->status;
    
        return $builder->where('status', $lastPostStatus);
    }
    

    【讨论】:

    • 嗨,谢谢你的回答,但不,那不是我想要的。我需要“其最新状态满足条件的所有帖子”。我需要通过 hasMany 关系的属性过滤所有帖子,但只有 hasMany 的最后一个孩子
    【解决方案3】:

    按今天激活的项目过滤:

    public function scopeCurrentActive()
    {
        return $this->whereHas('other', function($q) {
            return $q->whereDate('activation', '==', Carbon::now()->toDateString());
        });
    }
    

    【讨论】:

      猜你喜欢
      • 2017-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      • 2014-01-15
      • 1970-01-01
      • 2021-10-18
      • 1970-01-01
      相关资源
      最近更新 更多