Eloquent 按关系筛选(仅最后一条记录)
Eloquent Filter by relationship (ONLY last record)
我将我的问题编辑得更明确
我需要构建一个范围来过滤 hasMany 关系。问题是,我想将该查询应用于 last 项 ONLY,我的意思是,我希望我的模型按特定记录的列过滤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);
});
});
}
而不是
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());
});
}
要按今天激活的项目进行过滤,请写:
public function scopeCurrentActive()
{
return $this->whereHas('other', function($q) {
return $q->whereDate('activation', '==', Carbon::now()->toDateString());
});
}
不确定每个记录的最后一条记录。
以下是获取所有与最新 post 具有相同状态的 post 的方法:
public function scopeIsActive(Builder $builder)
{
$lastPostStatus = Post::select('status')
->orderBy('activation', 'desc')
->first()
->status;
return $builder->where('status', $lastPostStatus);
}
我将我的问题编辑得更明确
我需要构建一个范围来过滤 hasMany 关系。问题是,我想将该查询应用于 last 项 ONLY,我的意思是,我希望我的模型按特定记录的列过滤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);
});
});
}
而不是
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());
});
}
要按今天激活的项目进行过滤,请写:
public function scopeCurrentActive()
{
return $this->whereHas('other', function($q) {
return $q->whereDate('activation', '==', Carbon::now()->toDateString());
});
}
不确定每个记录的最后一条记录。
以下是获取所有与最新 post 具有相同状态的 post 的方法:
public function scopeIsActive(Builder $builder)
{
$lastPostStatus = Post::select('status')
->orderBy('activation', 'desc')
->first()
->status;
return $builder->where('status', $lastPostStatus);
}