Hello I have a little problem with eloquent in Laravel 5.
I have this function:
$lists = Model::with(array('relation_with_registered_in_model'=>function($query){
$query->where("name","cccc");
}))->get();
My poblem is that return always all results, ignoring where clause.
I tried to print my query (generated with function) and if I execute the query in my phpmyadmin it return correct filtered results.
What I'm wrong?
You could try with single qoute
$lists = Model::with(array('relation_with_registered_in_model'=>function($query){
$query->where('name','cccc');
}))->get();
I have resolved and Understand my error:
In this posts it is explained https://laracasts.com/discuss/channels/general-discussion/problem-with-the-eager-loading-of-laravel-eloquent-orm?page=1
// gets only models that have relation matching the closure constraint
// no eager loading of the relation!
Model::whereHas('relation', function ($q) { ...} );
// gets ALL models
// and eager loads the relation, but only rows matching the constraint
Model::with(['relation' => function ($q) { ...} ]);
Related
I currently have an Eloquent ORM query.
$uploadedSC = SC::select('id')->with(['cont'=> function ($q) {
return $q->with('crs:id,title')->select('*');
}])->where('act', true)->get();
But I wanna add a ->where('act',true) query to my crs table. However, it gives an error. How can I write this query?
$uploadedSC = SC::select('id')->with(['cont'=> function ($q) {
return $q->with('crs:id,title')->where('act',true)->select('*');
}])->where('act', true)->get();
You could do something like this:
$uploadedSC = SC::select('id')
->with(['cont.crs:id,title' => function ($crs) {
$crs->where('act', true);
}])
->where('act', true)
->get();
Depending on the direction of the relationship you must select the foreign key of cont in crs or you will receive an error. This is the problem of giving bad names to your models and tables, other programmers will not understand at the first time what you are trying to do.
My target is to get collection of books with count of matches book.names in another table without relation
I get collection like this
$books = Books::paginate(20);
What I need now is to get the count of matches like this
SELECT COUNT(*) FROM `posts` WHERE `body` LIKE '%book.name%'
How can I do this with one query and avoiding unnecessary queries for each model, like eager loading
You can do it with eager loading without loading all post. There is a method called withCount
Books.php
public function posts() {
return $this->hasMany(Post::class, 'post_id', 'id');
}
One way to find all post related to book is
$books = Books::withCount(['posts' => function ($query) use($searchTerm) {
$query->where('body', 'like', $searchTerm);
}])->get();
//How to retrieve
$book = $books->first()->posts_count.
You can find more information about withCount on laravel documentation website.
Approach 2: Without Eager Loading
$books = Books::select('*')->addSelect(DB::raw("SELECT COUNT(*) as post_count FROM `posts` WHERE `body` LIKE '%book.name%' ")->get(); //This will return collection with post_count.
Note: Not tested
Here is my query:
$profile = \App\ShippingProfile::findOrFail(2)
::with('costs')
->with( ['methods.zone' => function($query) {
$query->where('id', 2);
}])->get();
So I need shipping profile id 2, with related "costs" model and its related "method" with id 2, and the method's related "zone".
But I don't know how to get the result. If I try ->get() , I get all ShippingProfiles, and if try
->first() I get profile id 1.
So how would I retrieve the results? I have only seen "get", "first" and "find"...or is there something wrong with the query?
There are a few problems with your current code. First of all you have a syntax error:
$profile = \App\ShippingProfile::findOrFail(2)
::with('costs')
The second :: should be ->.
Secondly, when you do firstOrFail() you're actually executing the query and returning a Model as a result. So when you're then chaining the rest onto the Model instance you're likely ending up with an error.
There are a couple of ways you can achieve your goal however. First of all, try using whereKey which adds a where clause to your query against the primary key, (just like using findOrFail does - but it doesn't immediately execute the query and return the model) and use first() to grab the model instance with the relations eager loaded:
$profile = \App\ShippingProfile::whereKey(2)
->with(['costs', 'method.zone' => function ($query) {
$query->where('id', 2);
}])
->first();
Alternatively, if you already have an instance of your model, you can use load(...), in the same way as you would use with(...) to load your relations:
$profile = App\ShippingProfile::findOrFail(2);
$profile->load(['costs', 'method.zone' => function ($query) {
$query->where('id', 2);
}]);
Im trying to make a query using whereHas with eloquent. The query is like this:
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})
->with('investments')
->get();
Im using Laravel 5.2 using a Postgres driver.
The Project model is:
public function investments()
{
return $this->hasMany('App\Investment');
}
The investments model has:
public function project() {
return $this->belongsTo('App\Project');
}
The projects table has fields id,fields...
The investments table has the fields id,project_id,status,created_at
My issue is that the query runs and returns a collection of the projects which have at least one investment, however the where clause inside the whereHas is ignored, because the resulting collection includes investments with status values different than paid.
Does anyone has any idea of what is going on?
I believe this is what you need
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})->with(['investments' => function($q) {
$q->where('status','=','paid');
}])->get();
whereHas wil check all projects that have paid investments, with will eagerload all those investments.
You're confusing whereHas and with.
The with method will let you load the relationship only if the query returns true.
The whereHas method will let you get only the models which have the relationship which returns true to the query.
So you need to only use with and not mix with with whereHas:
$projects = Project::with(['investments' =>
function($query){ $query->where('status','=','paid'); }])
->get();
Try like this:
$projects = Project::with('investments')->whereHas('investments', function($q) {
$q->where('status','like','paid'); //strings are compared with wildcards.
})
->get();
Change the order. Use with() before the whereHas(). I had a similar problem few weeks ago. Btw, is the only real difference between the problem and the functional example that you made.
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.