I have comments table where has parent_id
This is Comment table sub_comments relation.
public function sub_comments()
{
return $this->hasMany(self::class, 'parent_id');
}
This code return all comments with related all sub-comments
Comment::with('sub_comments')->get();
But I want to get all comments also sub-comments when sub-comments is single. That mean if comment have 2 or more comments for that comment I did not want get that sub-comments.
Now I use this code
$oneSubcommentCommentIds = Comment::has('sub_comments', '=', 1)->pluck('id');
Comment::with([
'sub_comments' => function ($q) use ($oneSubcommentCommentIds) {
$q->whereIn('parent_id', $oneSubcommentCommentIds);
}
])->get();
but this make one additional query.
Try this:
Comment::with('sub_comments')->has('sub_comments', '=', 1)->get();
Update
Your question wasn't clear, I can't imagine another way to doing this without previosly loaded the relationship or the count of the relationship.. so I'd do this:
// First get all your comments with an aditional count field
$comments = Comments::withCount('sub_comments')->get();
// separate the ones with just one sub_comment from the rest
list($oneSubComment, $theRest) = $collection->partition(function ($comment) {
return $comment->sub_comments_count == 1;
});
// Then load the relationship on just the selected elements
$oneSubComment->load('sub_comments');
// re-join the collection
$comments = $oneSubComment->union($theRest);
What am I doing here?
Adding an additional field to each $comment with the relationship count (it should be something like sub_comments_count)
Partition the resulting collection in two parts: the ones with one comment and the rest. Using the partition() method.
Lazy eager loading the collection.
Re-joining the two collections using the union() method.
Related
I'm trying to retrieve a (paginated) list of posts and include their most recent comments in one Eloquent query statement. Posts and comments are connected by a one to many relationship.
This was my attempt:
Post::with(['comments' => function ($query) {
$query->orderBy('created_at', 'asc')->take(3);
}])->simplePaginate(15);
But that only retrieves 3 comments in total, not 3 comments per post.
Joined table Id is necessary
Try this:
Post::with(array('comments'=>function($query){
$query->select('id as commentid','comment')->orderBy('created_at', 'asc')->take(3);
}))->simplePaginate(15);
UPDATED
It seems you can not do it with 1 query.
You still can have this function in the parent model, called "lastComments":
function lastComments()
{
return $this->hasMany('App\Post', 'post_id')->orderBy('created_at')->take(3);
}
You load posts with normal eloquent code:
Post::simplePaginate(15);
And in the view page you show the comments in this way:
#foreach($post->lastComments as $comment)
<!-- ... -->
#endforeach
You need to set the $with variable in your App\Post model:
protected $with = ['lastComments'];
This way whenever you fetch a post, Laravel will automatically load the comments for it.
I have the following relationships:
TheEpisodeJob hasOne TheEpisode
TheEpisodeJob hasMany TheJobs
I am successfuly retrieving all TheEpisodesJobs and TheSeriesEpisodes with all the fields in database (including sensitive information) using this command:
$jobs = TheEpisodeJob::with('TheEpisode')->get();
I would like to limit TheEpisode fields shown only for this case (public $hidden will not work)
EDIT
Let's say I need only title and description field from TheEpisode.
How can I achieve that?
As #Buglinjo pointed out you can scope the relationship when eager loading, however, if you're going to be doing this to only select specific columns you must included the related column in the select so that Eloquent knows which Model to attach the related data to.
This should give you what you want:
$jobs = TheEpisodeJob::with(['TheEpisode' => function ($query) {
$query->select('jobID', 'title', 'description');
}])->get();
Furthermore, if you then wanted to to get rid of the jobID as well you could do something like:
$jobs->transform(function ($job) {
$job->TheEpisode->transform(function ($item) {
unset($item->jobID);
return $item;
});
return $job;
});
Hope this helps!
As far as I understood you, you want to limit the results according to some more parameters. If I am right, you should add more queries, like:
->where, ->orwhere, ->select, ->whereNull
Here is the link for more queries. Hope it will help )
I saw an update, so then you need
->pluck('title', 'description');
for more information, go to the link above
You should do like this:
$jobs = TheEpisodeJob::with(['TheEpisode' => function($q){
$q->get(['title', 'description']);
//or
$q->pluck('title', 'description');
}])->get();
Note: pluck is getting as array not as Eloquent Object.
I have got three tables in laravel like so:
Users, posts, and comments
I'm trying to come up with a query that fetches me all the user's posts, plus the date of last comment with each post.
Approach i've taken that's not working perfectly is:
$posts = User::find($userId)->posts()->with('latestComment')->get();
In my Post model I have:
public function latestComment()
{
return $this->hasOne(Comment::class)->latest();
}
In my findings, i haven't been to see a way to get the date from the lastComment load.
Any pointers welcome,
Thanks
Just discovered one needs to add the foreign key to the select method like so:
return $this->hasOne(Comment::class)->latest()->select('field','foreign_key');
You should use eager loading constraint. Code from the other answers will first load all comments, which you don't want.
$posts = Post::where('user_id', $userId)
->with(['comments' => function($q) {
$q->taletst()->take(1);
}])
->get();
You can use the existing relationship and get the latest comment.
public function comments() {
return $this->hasMany(Comment::class);
}
public function latestComment() {
return $this->comments()->last();
}
I want to limit related records from
$categories = Category::with('exams')->get();
this will get me exams from all categories but what i would like is to get 5 exams from one category and for each category.
Category Model
public function Exams() {
return $this->hasMany('Exam');
}
Exam Model
public function category () {
return $this->belongsTo('Category');
}
I have tried couple of things but couldnt get it to work
First what i found is something like this
$categories = Category::with(['exams' => function($exams){
$exams->limit(5);
}])->get();
But the problem with this is it will only get me 5 records from all categories. Also i have tried to add limit to Category model
public function Exams() {
return $this->hasMany('Exam')->limit(5);
}
But this doesnt do anything and returns as tough it didnt have limit 5.
So is there a way i could do this with Eloquent or should i simply load everything (would like to pass on that) and use break with foreach?
There is no way to do this using Eloquent's eager loading. The options you have are:
Fetch categories with all examps and take only 5 exams for each of them:
$categories = Category::with('exams')->get()->map(function($category) {
$category->exams = $category->exams->take(5);
return $category;
});
It should be ok, as long as you do not have too much exam data in your database - "too much" will vary between projects, just best try and see if it's fast enough for you.
Fetch only categories and then fetch 5 exams for each of them with $category->exams. This will result in more queries being executed - one additional query per fetched category.
I just insert small logic inside it which is working for me.
$categories = Category::with('exams');
Step 1: I count the records which are coming in response
$totalRecordCount = $categories->count()
Step 2: Pass total count inside the with function
$categories->with([
'exams' => function($query) use($totalRecordCount){
$query->take(5*$totalRecordCount);
}
])
Step 3: Now you can retrieve the result as per requirement
$categories->get();
I can't find how to get all of the elements with relations to another element using Eloquent in Laravel.
I have Substances and Contents and want all the contents related to the substances with name 'subst'.
My relation Substance - Content:
public function relation ()
{
return $this->belongsToMany('Substance', 'contents_substances', 'id_contents', 'id_substances');
}
public function relation ()
{
return $this->belongsToMany('Content', 'contents_substances', 'id_contents', 'id_substances');
}
I know I can get all the contents related to one substance:
$content = Substance::find(1)->relation()->get();
but is possible to get all the contents related to a group of substances?
something like:
$sub = Substance::where('name', '=', 'subst'); // get all the substances with that name
$contents =$sub->relation()->get(); // ???
Any help is appreciated!
The easiest is to start the query from the other angle. In this case from Content. whereHas will then add a constraint based on the substances relation:
$contents = Content::whereHas('substances', function($q){
$q->where('name', 'subst');
})->get();