Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel - Limit each child item efficiently

I have this:

$commentReplies = Comment::whereIn('comment_parent_id', $CommentsIDs)
                                  ->take(2)->get();

Where $CommentsIDs is an array of 3 parent comment ids (1,2,3).

I am trying to retrieve 2 replies for each of the $commentsIDs if they exist. So a total of 6 replies (2 for each comment) should come back with the query, if the replies exist, nothing more. However, with take(2) in there, it limits the replies to 2, and we only get 2 replies for one of the comments. How can it be setup to get 2 replies for each of the comment IDs in the most efficient way, and how can they get rendered in the view with the correct nesting?

Something like:

Comment 1
--Comment 1 Reply 1 (load this)
--Comment 1 Reply 2 (load this)
--Comment 1 Reply 3 (don't load this)
--Comment 1 Reply 4 (don't load this)
Comment 2
--Comment 2 Reply 1 (load this)
--Comment 2 Reply 2 (load this)
--Comment 2 Reply 3 (don't load this)
Comment 3
(no replies, don't load anything)

Update:
Here is the Comment Model:

class Comment extends BaseModel {

 public function latestTwoComments()
 {
     return $this->hasMany('Comment','comment_parent_id')->latest()->nPerGroup('comment_parent_id', 2);
 }

}

Query:

$comments = Comment::with('latestTwoComments')->get();
dd(DB::getQueryLog());

// Result:
'query' => string 'select * from (select `comments`.*, @rank := IF(@group = comment_parent_id, @rank+1, 1) as rank_575b053fb57f8fab5bc86dd324b39b91, @group := comment_parent_id as group_575b053fb57f8fab5bc86dd324b39b91 from (SELECT @rank:=0, @group:=0) as vars, comments where `comments`.`deleted_at` is null order by `comment_parent_id` asc, `created_at` desc) as comments where `comments`.`deleted_at` is null and `rank_575b053fb57f8fab5bc86dd324b39b91` <= ? and `comments`.`comment_parent_id` in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?'... (length=603)
like image 659
Wonka Avatar asked Oct 08 '14 00:10

Wonka


1 Answers

You can't use limit/skip when eager loading, for it will limit whole related result.

I suppose you use MySQL, so here is what you need: http://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/

It's way to long to paste here, so just to get the idea: You need MySQL variables to do the job of fetching n per parent for you, like:

public function latestTwoComments()
{
  return $this->hasMany('Comment', 'comment_parent_id')->latest()->nPerGroup('comment_parent_id', 2);
}

//then
$comments = Comment::with('latestTwoComments')->get();
// now all the comments will have at most 2 related child-comments

Note: it's meant for hasMany relation and MySQL

like image 116
Jarek Tkaczyk Avatar answered Nov 10 '22 03:11

Jarek Tkaczyk