28

In Laravel 4.2 I have a model called Product with many-to-many relationshis to other models like Country or Category. I want to filter out products that are "incomplete", which means they have no connected countries or no connected categories. I can use whereDoesntHave() method to filter out one relation. When I use it two times in one query it creates AND condition, but I need OR. I can't find orWhereDoesntHave() method in API documentation. I can't pass multiple relations as arguments because it expects first argument to be a string.

I need something like this: $products = Product::whereDoesntHave('categories')->orWhereDoesntHave('countries')->get();

Is there any way to achive whereDoesntHave() with multiple OR conditions?

KazikM
  • 1,257
  • 5
  • 21
  • 29

4 Answers4

48

You can use doesntHave and specify the boolean operator:

$products = Product::doesntHave('categories')->doesntHave('countries', 'or')->get();

Actually you only need whereDoesntHave if you want to pass in a closure to filter the related models before checking if any of them exist. In case you want to do that you can pass the closure as third argument:

$products = Product::doesntHave('categories', 'or', function($q){
    $q->where('active', false);
})->doesntHave('countries', 'or')->get();
lukasgeiter
  • 147,337
  • 26
  • 332
  • 270
  • 1
    Thanks, I missed `doesntHave()` while reading API. Your first code example is just what I need. – KazikM Jan 21 '15 at 13:33
28

Since Laravel 5.5 there is an orWhereDoesntHave function.

You may use it like this

Product::whereDoesntHave('categories', function($q){ //... })
       ->orWhereDoesntHave('countries', function($q){//...})
       ->get();

From you example it seems that you are not using a where clause, so you may just use

Product::doesntHave('categories')
       ->orDoesntHave('countries')
       ->get();
Laurel
  • 5,965
  • 14
  • 31
  • 57
Adam
  • 25,960
  • 22
  • 158
  • 247
4

Use

Product::whereDoesntHave('categories')->doesntHave('countries', 'or')->get();

Laravel Source Code:

whereDoesntHave https://github.com/illuminate/database/blob/master/Eloquent/Builder.php#L654 calls https://github.com/illuminate/database/blob/master/Eloquent/Builder.php#L628 internally.

Jan P.
  • 3,261
  • 19
  • 26
4

Let’s say we have Authors and Books, with 1-n relationship – one Author can have one or many Books. Here’s how it looks in app\Author.php:

 public function books()
    {
        return $this->hasMany(\App\Book::class, 'author_id');
    }

Now, what if we want to show only those Authors that have at least one book? Simple, there’s method has():

$authors = Author::has('books')->get();

Similarly, there’s an opposite method – what if we want to query only the authors without any books? Use doesnthave():

  $authors = Author::doesnthave('books')->get();

It’s not only convenient, but also super-easy to read and understand, even if you’re not a Laravel developer, right?

Hadayat Niazi
  • 1,991
  • 3
  • 16
  • 28