Reputation: 2105
I have a problem with Laravel 5.3 eager loaded relations using method with().
Either I do something wrong, or I understand it wrong.
I run this code:
$result = Post::with(['comments' => function ($query) { $query->where('content', 'like', '"%blanditiisx%"'); }])->get();
By checking database table 'comments' empirically, I know, that there is only single comment that has word 'blanditiisx' in its column 'content'.
So, since given comment can belong only to one post and we have only one comment matching 'where' condition, I was looking to get only one post.
To my surprise, above code returns all posts I have in database.
I would appreciate, if someone could tell me where I am going wrong with it.
Here is what I am working with:
POST
I have Post class with this relationship defined in it:
/** * One to Many relation * * @return \Illuminate\Database\Eloquent\Relations\hasMany */ public function comments() { return $this->hasMany(Comment::class); }
It works with this posts table:
+------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | | title | varchar(255) | NO | | NULL | | | slug | varchar(255) | NO | UNI | NULL | | | summary | text | NO | | NULL | | | content | text | NO | | NULL | | | seen | tinyint(1) | NO | | 0 | | | active | tinyint(1) | NO | | 0 | | | user_id | int(10) unsigned | NO | MUL | NULL | | +------------+------------------+------+-----+---------+----------------+
COMMENT
I have Comment class with this relationship defined in it:
/** * One to Many relation * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function post() { return $this->belongsTo(Post::class); }
It works with this comments table:
+------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | | content | text | NO | | NULL | | | seen | tinyint(1) | NO | | 0 | | | user_id | int(10) unsigned | NO | MUL | NULL | | | post_id | int(10) unsigned | NO | MUL | NULL | | | deleted_at | timestamp | YES | | NULL | | +------------+------------------+------+-----+---------+----------------+
EDIT:
Actually my initial code works, it just returns results in a way that got me confused.
What it does is it returns one collection for each post.
Most of them are empty. Only those collections, that fall within constraints of query are filled with data.
Rest are empty, but still fetched, so to filter them out one may use count().
And of course, they are eager.
Upvotes: 1
Views: 635
Reputation: 17658
You can try whereHas()
for this as:
$result = Post::whereHas('comments', function ($query) {
$query->where('content', 'like', '"%blanditiisx%"');
})->with('comments')->get();
It allows adding customized constraints to a relationship constraint, such as checking the content of a comment.
Or try as:
Post::whereHas('comments', function ($query) {
$query->where('content', 'like', '"%blanditiisx%"');
})
->with(['comments' => function ($query) {
$query->where('content', 'like', '"%blanditiisx%"');
}])
->get();
Upvotes: 4
Reputation: 31
The with() method is for preloading related data, not filtering the query you already have. See the whereHas() method for the filtering you're looking for.
Upvotes: 0