Cakephp 3 NOT IN query
If you want to use a subquery, simply pass a query object as the condition value, like
$subquery = $Courses->CoursesMemberships
->find()
->select(['CoursesMemberships.course_id'])
->where(['CoursesMemberships.student_id' => $student_id]);
$query = $Courses
->find()
->where([
'Courses.id NOT IN' => $subquery
]);
As an alternative there's also Query::notMatching()
(as of CakePHP 3.1), which can be used to select records whichs associated records do not match specific conditions:
$query = $Courses
->find()
->notMatching('CoursesMemberships', function (\Cake\ORM\Query $query) use ($student_id) {
return $query
->where(['CoursesMemberships.student_id' => $student_id]);
});
See also
- Cookbook > Database Access & ORM > Query Builder > Subqueries
- Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Using notMatching
- Cookbook > Database Access & ORM > Query Builder > Filtering by Associated Data
In CakePHP 3 you can create NOT IN
query like this.
$query = $Courses->find()
->where(['id NOT IN' => $ids]);
And in CakePHP 3 you can create IN
query like this.
$query = $Courses->find()
->where(['id IN' => $ids]);
You can read about it in CakePHP 3 Cookbook - Creating IN Clauses.
Found IMO the most elegant answer... use the notMatching() option:
$data = $this->Courses->find("list")
->notMatching("Students",
function($q) use ($student_id) {
return $q->where(["Students.id"=>$student_id]);
}
);
This assumes that Students HasMany Courses and Courses HasMany Students of course.
I think this is the most elegant answer since it doesn't depend on knowing any SQL, and represents the logic of what I'm trying to achieve using Cake's semantics only.