Manzoor-Bajwa's avatar

Eloquent nested relations with where clause

Hi I am trying to use $query->where(); in Eloquent nested relations. What i have done so far is:

$books = Book::with(['author.contacts' => function($query) {
    $query->where('is_deleted', 'N');
}])->get();

But the problem with above code is $query->where('is_deleted', 'N'); applies to the contacts table and I want to use some where clauses for authors table too. Like, I want to check if the author is_online etc.

Thanks

0 likes
24 replies
bobbybouwmann's avatar

You can simply do this

$books = Book::with(['author' => function($query) {
    $query->where('something', 'something');
}, 'author.contacts' => function($query) {
    $query->where('is_deleted', 'N');
}])->get();
15 likes
pmall's avatar

Use whereHas (can be nested) :

$books = Book::whereHas('author', function($query) {
    $query->where('is_online', 'Y')->whereHas('contacts', function ($query) {
        $query->where('is_deleted', 'N');
    });
}])->get();
4 likes
Manzoor-Bajwa's avatar

Thanks @bobbybouwmann , I've tried this

$books = Book::with(['author' => function($query) {
    $query->where('is_deleted', 'N');
}, 'author.contacts' => function($query) {
    $query->where('is_deleted', 'N');
}])->get();

but still getting the deleted author in the result set. I think 'author.contacts' => function($query) { ... } overrides the result set returned by 'author' => function($query) { .... } .

pmall's avatar

So :

$cb = function ($query)
{
    $query->where('is_deleted', 'N');
};

$books = Book::with(['author.contact' => $cb)->whereHas('author', function($query) use ($cb) {

    $query->where('is_online', 'Y')->whereHas('contacts', $cb);

}])->get();
Manzoor-Bajwa's avatar

@pmall I've tried your second answer and still getting the deleted user with no result set for auth_tokens table. Here is what i have tried

$notExpiredCheck = function($query) {
                                $query->notExpired();
                            };

return $query->with(['user.authToken' => $notExpiredCheck])
                        ->whereHas('user', function($query) use($select, $notExpiredCheck) {
                            User::select($select)
                            ->userGroup(UserGroup::$consumerGroupId)
                            ->notDeleted()
                            ->enabled()
                            ->active()
                            ->online()
                            ->having('distance', '<', User::$radius)
                            ->orderBy('distance', 'ASC')
                            ->whereHas('authToken', $notExpiredCheck);
                        })
                        ->get();
pmall's avatar

What ? This is a completely different query from what you asked at first

Manzoor-Bajwa's avatar

it just has some extra where / scope method calls but the scenario is same.

pmall's avatar

please fully explain what you want to do

pmall's avatar

Soft delete mechanism in laravel automatically add the where clause for not retrieving the soft deleted lines.

Manzoor-Bajwa's avatar

@bobbybouwmann please take a look at DB schema, I need to use (e.g.) $query->where('is_deleted', 'N') for all tables except auth_tokens table. I am just asking how to use where clauses for each relation. I read the documentation before posting question here and couldn't find any solution.

bobbybouwmann's avatar

Just at the where statement to each relation?

$cb = function ($query) {
    $query->where('is_deleted', 'N');
};

$books = Book::with(['author' => $cb, 'author.contact' => $cb])->get();
1 like
Manzoor-Bajwa's avatar

As i already said, that doesn't work at all. When i try to run

$books = Book::with(['author' => $cb, 'author.contact' => $cb])->get();

the result set of authors table returned by first relation i.e. author is overridden by the second relation i.e. author.contact. Actually author.contact returns both result sets 1)- For authors table 2)- For contacts table

That is why I am not getting desired results.

1 like
CodeNathan's avatar

@Manzoor-Bajwa @timrpeterson

I know this is old but this should work

        $books = Book::with('author.contacts')->whereHas( 'author.contacts', function($query) {
            $query->where('is_deleted', 'N');
        })->get();
zeshan77's avatar

I understand that this is an old post but it might help others:

Book::with(['author' => function($author) {

    $author->where('is_online', 1);
//...
    $author->with('contacts');

}])
->get();

Hope it helps!

2 likes
mungpara's avatar

@manzoor-bajwa try this

$books  = Book::with(['author' => function ($query) {
		// auther condition
        $query->where('is_active', 0);
        $query->with(['contacts' => function ($q2) {
			// contacts condition
            $q2->where('is_active', 1);
        }]);
    }])->get();

Please or to participate in this conversation.