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
相关产品推荐
相关产品推荐

