If you were using Oracle RDBMS I'd say use CONNECT BY PRIOR but I'm guessing MySQL.
Here is a little guide for hierarchical queries.
https://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
I have nested comments in my Laravel app (the Comment model is polymorphic, ie, the comment can be made to either a Post, or a Comment, as you can see in the example below with commentable_id and commentable_type)
id comment_hash commentable_type commentable_id
17 cmpipb0 App\Comment 15
15 cmpipap App\Comment 11
11 cmpipa4 App\Comment 1
1 cmpip7n App\Post 5
Note: I am not storing (nor do I intend to store) the post_id as a separate field with each comment in the comments table.
Given a comment (#17 in this example), I need to recursively go "up" the tree of comments until I get the id / details of the Post that the comment belongs to. In the above example, we will be given the comment_hash "cmpipb0" for comment id#17, and I would like to get the Post with id "5", which is at the top of the tree of nested comments.
comment id #17 (with comment_hash: cmpipb0) which is the child of:
comment id #15 (with comment_hash: cmpipap) which is the child of:
comment id #11 (with comment_hash: cmpipa4) which is the child of:
comment id #1 (with comment_hash: cmpip7n) which is the child of:
post id #5
My Model code is below:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Comment extends Model
{
use SoftDeletes;
public $table = 'comments';
protected $dates = [
'created_at',
'updated_at',
'deleted_at',
];
protected $fillable = [
'commentable_id',
'commentable_type',
'body',
'user_id',
'created_at',
'updated_at',
'deleted_at',
'comment_hash',
];
/**
* Customize the primary key for comment model.
* Enabling this results in 'out of memory'. See https://laracasts.com/discuss/channels/eloquent/changing-primary-key-of-a-polymorphic-comments-table-from-id-to-a-varchar-php-runs-out-of-memory
*/
// protected $primaryKey = 'comment_hash';
/**
* Get the owning commentable model.
*/
public function commentable()
{
return $this->morphTo();
}
/**
* Get all of the comments (single-level, not recursively)
*/
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model implements HasMedia
{
public $table = 'posts';
protected $dates = [
'created_at',
'updated_at',
'deleted_at',
];
protected $fillable = [
'slug',
'body',
'title',
'user_id',
'updated_at',
'created_at',
'deleted_at',
];
/**
* Get all of the post's comments.
*/
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
}
What is the best way to do this in Laravel?
One more thing.
If you want to profile theses queries in your project:
SELECT post_id
FROM (
SELECT
@post_id := (SELECT commentable_id FROM comments WHERE id = @comment_id and commentable_type = 'App\\Post') AS post_id,
@comment_id := (SELECT commentable_id FROM comments WHERE id = @comment_id and commentable_type = 'App\\Comment') AS comment_id
FROM
comments, (SELECT @comment_id := 3500, @post_id := NULL) AS initialization
WHERE @post_id IS NULL
) AS recurse
WHERE post_id IS NOT NULL;
Other approach:
SELECT
commentable_id as post_id
from comments
WHERE id = (SELECT MIN(comment_id) FROM (SELECT
@comment_id := (SELECT commentable_id FROM comments WHERE id = @comment_id and commentable_type = 'App\Comment') AS comment_id
FROM
comments, (SELECT @comment_id := 3500, @post_id := NULL) AS initialization
WHERE @comment_id IS NOT NULL) AS recurse);
They took around 1 second to run on my machine on a comments table with about 125K records for a comment in the 20th level.
For a comment in the 5th level both queries run under 500ms.
In both scenarios the first query runs a bit faster than the second.
500ms to 1 second is a lot for user interaction, but if your need is to run in some kind of queued job or console command it might be ok depending on the frequency of those jobs/commands.
Also there might be some easy optimizations on the queries above as I am bit rust on writing this kind of queries.
Please or to participate in this conversation.