You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent查询:获取用户已完成的全部项目

解决思路:查询用户完成所有任务的项目

你的当前scopeIsCompleted存在两个核心问题:

  • 直接在作用域里调用了get(),这会立即执行查询并返回集合,破坏了Eloquent的链式查询能力
  • 逻辑上只筛选出了用户至少完成一个任务的项目,而非完成了该项目所有任务的项目

要实现目标,我们需要对比「项目总任务数」和「用户在该项目下完成的任务数」,当两者相等时,就说明用户完成了这个项目的所有任务。

步骤1:确保模型关联正确

先确认你的模型关联已经正确定义:

  • Project模型:
public function tasks()
{
    return $this->hasMany(Task::class);
}

public function userTasks()
{
    return $this->hasManyThrough(UserTask::class, Task::class);
}
  • Task模型:
public function userTasks()
{
    return $this->hasMany(UserTask::class);
}

步骤2:编写正确的查询作用域

修改你的scopeIsCompleted,用子查询或聚合函数来实现对比逻辑:

public function scopeIsCompleted($query)
{
    $userId = Auth::user()->id;

    // 1. 计算每个项目的总任务数
    $totalTasksSubquery = Task::selectRaw('count(*)')
        ->whereColumn('project_id', 'projects.id');

    // 2. 计算该用户在项目下完成的任务数
    $completedTasksSubquery = UserTask::selectRaw('count(distinct task_id)')
        ->join('tasks', 'tasks.id', '=', 'user_tasks.task_id')
        ->whereColumn('tasks.project_id', 'projects.id')
        ->where('user_tasks.user_id', $userId);

    // 3. 筛选总任务数等于完成任务数的项目
    return $query->select('projects.*')
        ->selectSub($totalTasksSubquery, 'total_tasks')
        ->selectSub($completedTasksSubquery, 'completed_tasks')
        ->havingRaw('total_tasks = completed_tasks')
        ->havingRaw('total_tasks > 0'); // 排除没有任务的项目(可选)
}

步骤3:使用这个作用域

现在你可以链式调用这个作用域,比如:

$completedProjects = Project::isCompleted()->get();

补充说明

  • 用count(distinct task_id)是为了避免同一个任务被用户重复标记完成的情况(如果你的业务允许重复标记的话)
  • havingRaw用来对比聚合后的数值,因为where无法直接使用聚合列
  • 不要在作用域里调用get(),保持作用域只负责构建查询,让调用方决定何时执行查询

内容的提问来源于stack exchange,提问作者Skintest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:57:23