Laravel Eloquent:如何获取特定用户未选修的课程(多对多关联)
Hey there! I feel your pain—spending hours searching for the right Eloquent query can be frustrating, especially with many-to-many relationships. Let’s walk through exactly how to get the courses a specific user hasn’t signed up for.
First, make sure your model relationships are set up correctly (I’m assuming you already have this, but it’s worth double-checking):
Step 1: Confirm Model Associations
In your User model:
class User extends Model { public function courses() { return $this->belongsToMany(Course::class); } }
In your Course model:
class Course extends Model { public function users() { return $this->belongsToMany(User::class); } }
Step 2: The Most Efficient Method — whereDoesntHave
Eloquent has a built-in method called whereDoesntHave that’s perfect for this scenario. It lets you query models that don’t have a specific related model record. Here’s how to use it:
// Replace with your target user's ID $targetUserId = 5; // Get all courses the user hasn't selected $unselectedCourses = Course::whereDoesntHave('users', function ($query) use ($targetUserId) { $query->where('users.id', $targetUserId); })->get();
Let me break this down:
whereDoesntHave('users')tells Eloquent to look for courses with no linked users...- ...but the closure narrows it down to only exclude the specific user (so we don’t get courses with zero students entirely).
Alternative Method — whereNotIn
If you prefer a more explicit approach, you can first grab the IDs of courses the user has selected, then filter courses that aren’t in that list:
$targetUserId = 5; // Get IDs of courses the user already takes $selectedCourseIds = User::find($targetUserId)->courses()->pluck('courses.id'); // Get all courses not in that ID list $unselectedCourses = Course::whereNotIn('id', $selectedCourseIds)->get();
This works, but note that it runs two separate database queries, whereas whereDoesntHave does it in one—so the first method is more efficient, especially with large datasets.
Pro Tip: Handle Non-Existent Users
Always add a check to make sure the user exists before running the query, to avoid errors:
$user = User::find($targetUserId); if (!$user) { // Handle the case where the user doesn't exist (e.g., return an empty collection or error) $unselectedCourses = collect(); } else { $unselectedCourses = Course::whereDoesntHave('users', fn($q) => $q->where('id', $user->id))->get(); }
That’s it! Both methods will give you exactly the courses the user hasn’t enrolled in.
内容的提问来源于stack exchange,提问作者Misbah Ahmad

