在Laravel中按数量排序的多对多态关系

Order by count in many to many polymorphic relation in Laravel

让我们以doc为例:https://laravel.com/docs/5.7/eloquent-relationships#many-to-many-polymorphic-relations很容易获得所有posts及其tags计数正在执行Post::withCount('tags')->get()

但是如何获取所有tags及其使用计数?按最常用/较少用的顺序排序。

如果我执行Tag::withCount(['video', 'post'])->get(),则将具有2个属性videos_countposts_count。就我而言,我想要一个唯一的taggables_count,这将是两者的总和。在理想情况下,通过添加子选择查询数据透视表。


因此,在进行更多搜索之后,我发现仅凭一个查询就无法执行此操作,原因是在mysql中我们无法对子子集结果进行选择。因此,执行Tag::withCount(['videos', 'posts'])并尝试对查询中的videos_countposts_count求和将不起作用。我最好的方法是创建一个在数据透视表中读取结果的作用域:

1
2
3
4
5
6
7
8
9
10
11
12
13
public function scopeWithTaggablesCount($query) {
    if (is_null($query->getQuery()->columns)) {
        $query->select($query->getQuery()->from . '.*');
    }

    $query->selectSub(function ($query) {
        $query->selectRaw('count(*)')
            ->from('taggables')
            ->whereColumn('taggables.tag_id', 'tags.id');
    }, 'taggables_count');

    return $query;
}

要使用它:

1
$tags = Tag::withTaggablesCount()->orderBy('name', 'ASC')->get();

因此,现在每个标签都有一个taggables_count,它可以用于order by。希望它可以帮助别人。


我建议您简单地执行您已经进行的通话,即Tag::withCount(['video', 'post'])->get(),并将其添加到您的Tag模型中:

1
2
3
4
5
6
7
8
9
10
11
// Tag.php
class Tag
{
  ...
  // Create an attribute that can be called using 'taggables_count'
  public function getTaggablesCountAttribute()
  {
    return $this->videos_count + $this->posts_count;
  }
  ...
}

,然后在循环中(或使用集合中的项目):

1
2
3
@foreach($tags as $tag)
  {{ $tag->taggables_count }}
@endforeach

此设置要求您使用withCount['video', 'post']来获取标签。如果不这样做,您可能会得到0作为$tag->taggables_count的回报。

如果您真的担心速度,则必须手动创建查询并在其中进行添加。