在我的数据库中,我有:
tops
桌子posts
桌子tops_has_posts
桌子。当我检索
tops
桌子上的顶部时,我还会检索有关顶部的 posts
。
但是如果我想按特定顺序检索这些帖子怎么办?
因此,我在数据透视表中添加了一个 range
字段 tops_has_posts
,并尝试使用 Eloquent 按结果进行排序,但没有成功。
我试试这个:
$top->articles()->whereHas('articles', function($q) {
$q->orderBy('range', 'ASC');
})->get()->toArray();
还有这个:
$top->articles()->orderBy('range', 'ASC')->get()->toArray();
两者都是绝望的尝试。
提前谢谢您。
有 2 种方法 - 一种是指定
table.field
,另一种是使用 Eloquent 别名 pivot_field
(如果您使用 withPivot('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()
。
在 Laravel 5.6+(不确定旧版本)中使用这个很方便:
public function articles()
{
return $this->belongsToMany('Article', 'tops_has_posts')->withPivot('range')->orderBy('tops_has_posts.range');
}
在这种情况下,每当您调用
articles
时,它们都会按 range
属性自动排序。
在 Laravel 5.4 我有以下关系,在
Set
模型中运行良好,其中 belongsToMany
模型的 Job
:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
上述关系返回指定
jobs
已按数据透视表 (Set
) 字段 eqtype_jobs
DESC 排序的所有 created_at
。
$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;
}
并在获取并使用 sortby 后将关键字属性附加到模型
$courses->get()->append('keyword_order')->sortBy('keyword_order');