如何通过Laravel的Eloquent ORM中的数据透视表数据进行排序

时间:2014-10-24 15:22:46

标签: php mysql laravel eloquent

在我的数据库中,我有:

  • 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();

两者都是绝望的尝试。

提前谢谢。

6 个答案:

答案 0 :(得分:13)

如果您使用table.field,有两种方法 - 一种使用指定pivot_field,另一种使用Eloquent别名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,我会使用其中一个或另一个名称,除非确实需要这个。

答案 1 :(得分:4)

在Laravel 5.6+(不确定旧版本)中使用它很方便:

public function articles()
{
  return $this->belongsToMany('Article', 'tops_has_posts')->withPivot('range')->orderBy('tops_has_posts.range');
}

在这种情况下,只要您拨打articles,他们就会被range属性自动排序。

答案 2 :(得分:3)

如果打印出belongsToMany关系的SQL查询,你会发现数据透视表的列名使用了pivot_前缀作为新的别名。

例如,数据透视表中的 created_atupdated_atpivot_created_atpivot_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_atpivot_updated_at

答案 3 :(得分:2)

在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)字段created_at DESC。

$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

答案 4 :(得分:1)

对于 Laravel 8.17.2 + ,您可以使用::orderByPivot()

https://github.com/laravel/framework/releases/tag/v8.17.2

答案 5 :(得分:0)

你的刀片中的

试试这个:

$top->articles()->orderBy('pivot_range','asc')->get();