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

Laravel如何基于讲座观看记录获取用户最近观看的10个课程

原代码存在的核心问题
  • 讲座查询语句末尾缺少->get()执行方法,$startedLectures是查询构造器实例,不是实际查询到的结果集
  • 循环逻辑完全错误:每次循环都直接覆盖$watchedCourses变量,且错误访问查询构造器的course_id属性而非遍历出的单条讲座属性,最终只会保留最后一次循环的查询结果,不可能拿到10条课程
  • 没有做课程去重:如果同一个课程下有多个未看完的讲座,会重复占用返回名额,无法凑够10个不同的课程
  • 预加载关联时没有筛选当前用户的观看记录,拿到课程数据后也无法直接定位到上次看到的具体讲座
可直接使用的修正代码

优先用Eloquent ORM实现,避免手写join的字段冲突问题,同时保证查询性能:

if (Auth::check()) {
    $userId = Auth::id();

    // 第一步:查询当前用户所有未看完的讲座,按课程去重,只保留每个课程最新的观看记录,取10条
    $latestViewRecords = Lecture::query()
        ->join('watches', 'lectures.id', '=', 'watches.lecture_id')
        ->join('modules', 'lectures.module_id', '=', 'modules.id')
        ->where('watches.user_id', $userId)
        ->where('watches.progress', '!=', '')
        ->where('watches.is_completed', 0)
        ->selectRaw('modules.course_id, max(watches.updated_at) as latest_watched_at, SUBSTRING_INDEX(GROUP_CONCAT(watches.lecture_id ORDER BY watches.updated_at DESC), ",", 1) as latest_lecture_id')
        ->groupBy('modules.course_id')
        ->orderByDesc('latest_watched_at')
        ->limit(10)
        ->get();

    $targetCourseIds = $latestViewRecords->pluck('course_id');
    $courseViewMap = $latestViewRecords->keyBy('course_id');

    // 第二步:批量查询10个目标课程,预加载所需关联
    $watchedCourses = Course::query()
        ->whereIn('id', $targetCourseIds)
        // 预加载模块、按序号排序的讲座
        ->with([
            'modules' => function($q) {
                $q->orderBy('module_number', 'asc'); // 模块有排序字段则保留,没有可删除
            },
            'modules.lectures' => function($q) {
                $q->orderBy('lecture_number', 'asc');
            }
        ])
        ->get()
        // 按最近观看时间倒序排列,保证返回顺序符合"最近观看"逻辑
        ->sortByDesc(function($course) use ($courseViewMap) {
            return $courseViewMap[$course->id]->latest_watched_at;
        })
        ->values();

    // 第三步:给每个课程挂载上次观看的讲座信息,前端可直接调用
    $watchedCourses->each(function($course) use ($courseViewMap) {
        $record = $courseViewMap[$course->id];
        // 从预加载的讲座集合里找到对应最新观看的讲座,不用额外查库
        $course->last_view_lecture = $course->modules
            ->pluck('lectures')
            ->flatten()
            ->firstWhere('id', $record->latest_lecture_id);
    });
}
补充说明
  • 返回的$watchedCourses集合里每个课程实例都携带了last_view_lecture属性,点击课程跳转时直接取该讲座的ID即可实现定位
  • 所有查询都是批量执行,没有N+1问题,性能比循环查单门课程高很多
  • 如果你的模块、课程、讲座有软删除或上下架状态过滤,直接在对应查询的where条件里补充即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:15:37