If two tables have relationship between them, I am using with function to get records considering value within condition from another table. For example:
Table::where('column1', 'text1')->with('table2.column2', 'text2')
My question is, how can I use whereIn function to set array of allowed values in table2?
Table::where('column1', 'text1')->whereIn('table2.column2', ['text2', 'text3'])
Try this
Table::where('column1', 'text1')
->whereHas('table2',function($q) {
$q->whereIn('column2', ['text2','text3']);
});
You must have to define relationship in model
This is the best practice
Refer: Laravel Eloquent Relationship
Refer: Query On Relationship
I would go with Laravel's Constrained eager load to load your relationship.
Example
Table::where('column1', 'text1')
->with(['table2' => function ($query) {
$query->whereIn('column2', ['text2', 'text3'])
}])
->get();
If you don't need to load the relationship, then going with the whereHas solution provided by #bhavinjr is the best.
From the documentation :
Eager Loading Multiple Relationships
Sometimes you may need to eager load several different relationships in a single operation. To do so, just pass additional arguments to the with method:
$books = App\Book::with(['author', 'publisher'])->get();
Constraining Eager Loads
Sometimes you may wish to eager load a relationship, but also specify additional query conditions for the eager loading query. Here's an example:
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();`
You can take a look at Laravel API to have a deeper understanding of the with method.
Related
I know I can use the with method to eager load relationships. But how to determine "how many to load"?
For example, a Post model has many Comment, I want to load only 5 comments per post. Because a post could have thousands of comments I don't want to load them all. How could I do this?
If I can't do this with Laravel eloquent, what would a raw SQL would be for such a usecase?
Two ways.
Making the relationship itself limit the results.
public function comments()
{
return $this->hasMany(Comment::class)->limit(5);
}
Using a closure when eager loading to limit the results
Post::with(['comments' => function ($query) {
$query->limit(5);
})->get();
// or
Post::with(['comments' => fn($query) => $query->limit(5)])->get();
The second approach is better in my opinion.
Eloquent Relationships - Constraining Eager Loads
EDIT
According to this comment, you can limit the results but the syntax isn't very pretty.
Post::with(['comments'])->get()
->map(function ($query) {
$query->setRelation('comments', $query->comments->take(5));
return $query;
});
// or
Post::with(['comments'])->get()
->map(fn($query) => tap($query)->setRelation('comments', $query->comments->take(5)));
It's worth nothing this won't change the relationship query so if 5 posts had a total of a 1000 comments combined, it still queries the database for all 1000 comments.
Hi guys is it possible to do this in an eager loading?
Client::with(['relationship' => function($query){
$query->whereBetween('created_at', [$client->failed_date, Carbon::now()->endOfDay()])
}])->get();
Basically I want to put the failed_date column from my CLIENT model into the eager loading query.
Since all types of Eloquent relationships are defined via methods, you may call those methods to obtain an instance of the relationship without actually executing the relationship queries. In addition, all types of Eloquent relationships also serve as query builders, allowing you to continue to chain constraints onto the relationship query before finally executing the SQL against your database.
For example.
$clients = Client::where('status', 1)->get();
foreach($clients as $client) {
$relationships = $client->relationship()
->whereBetween('created_at', [$client->failed_date, $client->pass_date]);
}
This way you can solve your problem.
If you're trying to eagerly load your relationships, As eager load will perform a separate query you don't have direct access to the parent table, so you need to join it.
public function relationship()
{
return $this->belongsTo(Client::class)
->selectRaw('clients.*')
->join('relationships', 'clients.id', '=', 'relationships.client_id')
->whereRaw("....");
}
I have Project Model each Project has Many Positions from Position Model and each positions has Many Employees in Employee Model
Now I want to query all employees id's of the particular project regardless their position,
How can I achieve this using eloquent?
Roughly you would do something similar to this, where you can use whereHas to create nested queries on relations.
$employeeIdsToFilter = [1,2,3];
$filteredProjects = Project::query()->
whereHas('positions' , function ($query) use ($employeeIdsToFilter) {
$query->whereHas('employees', function($query) use ($employeeIdsToFilter) {
$query->whereIn('id', $employeeIdsToFilter);
});
})->get();
You can use the HasManyThough relation. Here is the Link
I have a many-to-many relationship between models. For a given model instance, I know how to filter the related models according to the value of a pivot. For example, in the case of users and roles, I would use:
User->roles()->wherePivot('admin',1);
Similarly, I know how to eager load all roles for a set of users:
User::where('active',1)->with('roles')->get();
What I am trying to do is combine these two concepts. For example, how do I retrieve a set of users with their eagerly loaded roles, where the users are filtered according to a field on the pivot?
I realise I can do this easily enough with raw SQL, but I would prefer to use Eloquent if possible.
You can restrict your eager loaded relations using a closure.
$users = User::with(['roles' => function ($query) {
return $query->wherePivot('admin', 1);
}])
->where('active', 1)
->get();
You can also query relations using whereHas.
$users = User::with('roles')
->whereHas('roles', function ($query) {
return $query->wherePivot('admin', 1);
})
->where('active', 1)
->get();
Pass a closure in to with when eager loading to add clauses to the query:
User::with(['roles' => function ($query) {
$query->where('admin', 1);
}])->where('active', 1)->get();
I want to filter the contents of two tables which have an Eloquent belongsToMany() to each other based on the created_at column in the pivot table that joins them. Based on this SO question I came up with the following:
$data = ModelA::with(['ModelB' => function ($q) {
$q->wherePivot('test', '=', 1);
}])->get();
Here I'm using a simple test column to check if it's working, this should be 'created_at'.
What happens though is that I get all the instances of ModelA with the ModelB information if it fits the criteria in the wherePivot(). This makes sense because it's exactly what I'm telling it to do.
My question is how do I limit the results returned based on only the single column in the pivot table? Specifically, I want to get all instances of ModelA and ModelB that were linked after a specific date.
OK, here it goes, since the other answer is still wrong.
First off, wherePivot won't work in whereHas closure. It's BelongsToManys method and works only on the relation object (so it works when eager loading).
$data = ModelA::with(['relation' => function ($q) use ($someDate) {
$q->wherePivot('created_at', '>', $someDate);
// or
// $q->where('pivot_table.created_at', '>', $someDate);
// or if the relation defines withPivot('created_at')
// $q->where('pivot_created_at', '>', $someDate);
}])->whereHas('ModelB', function ($q) use ($someDate) {
// wherePivot won't work here, so:
$q->where('pivot_table.created_at', '>', $someDate);
})->get();
You are using Eager Loading Constraints, which constrain only, like you said, the results of the related table.
What you want to use is whereHas:
$data = ModelA::whereHas('ModelB' => function ($q) {
$q->wherePivot('test', '=', 1);
})->get();
Be aware that ModelB here refers to the name of the relationship.