在我的数据库中,我有:
tops
表posts
表tops_has_posts
表
当我在tops
表上检索顶部时,我还检索与顶部相关的posts
。但是,如果我想按特定顺序检索这些帖子,该怎么办?因此,我在数据透视表tops_has_posts
中添加了一个range
字段,并尝试使用Eloquent按结果排序,但它不起作用。
我试试这个:
$top->articles()->whereHas('articles', function($q) {
$q->orderBy('range', 'ASC');
})->get()->toArray();
这个:
$top->articles()->orderBy('range', 'ASC')->get()->toArray();
这两次都是绝望的尝试。
提前谢谢。
有两种方法-一种是指定table.field
,另一种是如果使用withPivot('field')
:,则使用Eloquent别名pivot_field
// if you use withPivot
public function articles()
{
return $this->belongsToMany('Article', 'tops_has_posts')->withPivot('range');
}
// then: (with not whereHas)
$top = Top::with(['articles' => function ($q) {
$q->orderBy('pivot_range', 'asc');
}])->first(); // or get() or whatever
这将起作用,因为Eloquent将withPivot
中提供的所有字段别名为pivot_field_name
。
现在,通用解决方案:
$top = Top::with(['articles' => function ($q) {
$q->orderBy('tops_has_posts.range', 'asc');
}])->first(); // or get() or whatever
// or:
$top = Top::first();
$articles = $top->articles()->orderBy('tops_has_posts.range', 'asc')->get();
这将对相关查询进行排序。
注意:不要用这种方式命名事物,让你的生活变得艰难。posts
不一定是articles
,除非真的需要,否则我会使用其中一个或另一个名称。
对于Laravel 8.17.2+,您可以使用::orderByPivot()
。
https://github.com/laravel/framework/releases/tag/v8.17.2
在Laravel 5.6+(不确定旧版本)中,使用以下内容很方便:
public function articles()
{
return $this->belongsToMany('Article', 'tops_has_posts')->withPivot('range')->orderBy('tops_has_posts.range');
}
在这种情况下,无论何时调用articles
,它们都将按range
属性自动排序。
在Laravel5.4中,我有以下关系,在Set
模型中运行良好,而在Job
模型的belongsToMany
中运行良好:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
上面的关系返回指定的Set
已经按照数据透视表的(eqtype_jobs
)字段created_at
DESC的顺序加入的所有jobs
$set->jobs()->paginate(20)
的SQL打印输出如下所示:
select
`jobs`.*, `eqtype_jobs`.`set_id` as `pivot_set_id`,
`eqtype_jobs`.`job_id` as `pivot_job_id`,
`eqtype_jobs`.`created_at` as `pivot_created_at`,
`eqtype_jobs`.`updated_at` as `pivot_updated_at`,
`eqtype_jobs`.`id` as `pivot_id`
from `jobs`
inner join `eqtype_jobs` on `jobs`.`id` = `eqtype_jobs`.`job_id`
where `eqtype_jobs`.`set_id` = 56
order by `pivot_created_at` desc
limit 20
offset 0
在您的刀片中尝试以下操作:
$top->articles()->orderBy('pivot_range','asc')->get();
如果打印出belongsToMany
关系的SQL查询,您会发现透视表的列名使用pivot_
前缀作为新的别名。
例如,透视表中的created_at
、updated_at
具有pivot_created_at
、pivot_updated_at
别名。因此orderBy
方法应该使用这些别名。
下面是一个如何做到这一点的例子。
class User {
...
public function posts(): BelongsToMany {
return $this->belongsToMany(
Post::class,
'post_user',
'user_id',
'post_id')
->withTimestamps()
->latest('pivot_created_at');
}
...
}
如果您愿意,可以使用orderBy
而不是latest
方法。在上面的示例中,post_user
是透视表,您可以看到用于排序的列名现在是pivot_created_at
或pivot_updated_at
。
您可以使用这个:
public function keywords() {
return $this->morphToMany('App'Models'Keyword::class, "keywordable")->withPivot('order');
}
public function getKeywordOrderAttribute() {
return $this->keywords()->first()->pivot->order;
}
并在获取后将关键字attribute附加到模型中,并使用排序
$courses->get()->append('keyword_order')->sortBy('keyword_order');