Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

rehman_invozone's avatar

query improvement

Hi, I need assistance in improving my query. what I'm doing getting nested self-relation records. here is my migration.

 Schema::create('menu_items', function($table) {
            $table->increments('id');
            $table->string('name');
            $table->string('url');
            $table->integer('parent_id')->unsigned()->nullable();
            $table->foreign('parent_id')->references('id')->on('menu_items');
            $table->timestamps();
        });

Relation in Model

 public function children()
    {
        return $this->hasMany(MenuItem::class, 'parent_id')->with('children');
    }

Query in Controller

MenuItem::where('parent_id',null)->with('children')->get();

The output I need.

  [
        {
            "id": 1,
            "name": "All events",
            "url": "/events",
            "parent_id": null,
            "created_at": "2021-04-27T15:35:15.000000Z",
            "updated_at": "2021-04-27T15:35:15.000000Z",
            "children": [
                {
                    "id": 2,
                    "name": "Laracon",
                    "url": "/events/laracon",
                    "parent_id": 1,
                    "created_at": "2021-04-27T15:35:15.000000Z",
                    "updated_at": "2021-04-27T15:35:15.000000Z",
                    "children": [
                        {
                            "id": 3,
                            "name": "Illuminate your knowledge of the laravel code base",
                            "url": "/events/laracon/workshops/illuminate",
                            "parent_id": 2,
                            "created_at": "2021-04-27T15:35:15.000000Z",
                            "updated_at": "2021-04-27T15:35:15.000000Z",
                            "children": []
                        },
                        {
                            "id": 4,
                            "name": "The new Eloquent - load more with less",
                            "url": "/events/laracon/workshops/eloquent",
                            "parent_id": 2,
                            "created_at": "2021-04-27T15:35:15.000000Z",
                            "updated_at": "2021-04-27T15:35:15.000000Z",
                            "children": []
                        }
                    ]
                },
                {
                    "id": 5,
                    "name": "Reactcon",
                    "url": "/events/reactcon",
                    "parent_id": 1,
                    "created_at": "2021-04-27T15:35:15.000000Z",
                    "updated_at": "2021-04-27T15:35:15.000000Z",
                    "children": [
                        {
                            "id": 6,
                            "name": "#NoClass pure functional programming",
                            "url": "/events/reactcon/workshops/noclass",
                            "parent_id": 5,
                            "created_at": "2021-04-27T15:35:15.000000Z",
                            "updated_at": "2021-04-27T15:35:15.000000Z",
                            "children": []
                        },
                        {
                            "id": 7,
                            "name": "Navigating the function jungle",
                            "url": "/events/reactcon/workshops/jungle",
                            "parent_id": 5,
                            "created_at": "2021-04-27T15:35:15.000000Z",
                            "updated_at": "2021-04-27T15:35:15.000000Z",
                            "children": []
                        }
                    ]
                }
            ]
        }
    ]

I am getting what I need with this query. I there any better way to do this if possible in one query?

0 likes
7 replies
Sinnbeck's avatar

I assume you are only getting 1 level deep and not 2 as in your example?

You can try

MenuItem::where('parent_id',null)->with('children.children')->get();
rehman_invozone's avatar

@Sinnbeck no I am getting the right output. I not about one to two levels. It can go up to any level. My question is am I doing this in the right way or is there any better way to do this?

rehman_invozone's avatar

@Sinnbeck Yes, I already have debug bar and the results are same even with

MenuItem::where('parent_id',null)->with('children.children')->get();

but I think you didn't get my question no problem thank you.

Please or to participate in this conversation.