雄辩的关系计数

时间:2014-08-01 15:42:47

标签: php laravel eloquent

我在使用Laravel 4和Elqouent时遇到了问题。我的模型实现了以下关系:

  

用户 belongsToMany 角色
  角色 belongsToMany 用户

我想查询角色,并希望获得相关用户的计数。

当我执行以下操作时,我遇到了N + 1问题:

$role = Role::has('users')->get()->each(function($role) {
    $role->user_count = $role->users()->count();
});

有什么我没想过的吗?

2 个答案:

答案 0 :(得分:1)

这是您belongsToMany所需要的:

// Role model

// helper relation
public function usersCount()
{
    return $this->belongsToMany('User')
      ->selectRaw('count(users.id) as count')
      ->groupBy('pivot_role_id');
}

// accessor for $role->usersCount;
public function getUsersCountAttribute()
{
    if ( ! array_key_exists('usersCount', $this->relations)) $this->load('usersCount');

    $related = $this->getRelation('usersCount')->first();

    return ($related) ? $related->count : 0;
}

然后你可以急于加载它:

$roles = Role::with('usersCount')->get();

// pick one, for example
$roles->first()->usersCount; // int
$roles->last()->usersCount; // 0 if no related users were found

不幸的是,您当前的解决方案非常糟糕,因为它会查询每个角色的数据库。

上面的代码允许您只使用一个查询来获取所有角色的计数。 另一件事是,如果没有必要,你不会加载所有相关用户,所以它不会占用你的记忆(如果它很重要)。

答案 1 :(得分:1)

尽管我很感谢你们帮助我,但不幸的是,你的解决方案都没有真正做到这一点。

我找到了另一个帮助我的question+answer

以下是完全符合我想要的解决方案:

Role::join('assigned_roles', 'assigned_roles.role_id', '=', 'roles.id')
        ->groupBy('roles.id')
        ->orderBy('user_count', 'desc')
        ->orderBy('name', 'asc')
        ->get(['roles.*', DB::raw('COUNT(assigned_roles.id) as user_count')]);