skip to Main Content

Help please…

These are my migrations

 // Test 1 table
    public function up(): void
    {
        Schema::create('test1s', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('desc')->nullable();
            $table->timestamps();
        });
    }



next...

// Test 2 table
    public function up(): void
    {
        Schema::create('test2s', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('desc')->nullable();
            $table->foreignId('test2_id')->references('id')->on('test1s')->onDelete('cascade');
            $table->timestamps();
        });
    }


next...


   // Test 3 table
    public function up(): void
    {
        Schema::create('test3s', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('desc')->nullable();
            $table->foreignId('test3_id')->references('id')->on('test2s')->onDelete('cascade');
            $table->timestamps();
        });
    }

Here are my models and methods in them

namespace AppModels;

use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;

class Test1 extends Model
{
    use HasFactory;

    public function method1(){
       return $this->hasMany(Test2::class, 'test2_id', 'id')->with('method2');
   }

namespace AppModels;

use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;

class Test2 extends Model
{
    use HasFactory;

    public function method2(){
      return $this->hasMany(Test3::class, 'test3_id', 'id');
    }
}

Here’s controller

namespace AppHttpControllers;

use IlluminateHttpRequest;
use AppModelsTest1;


class HomeController extends Controller
{
 
    public function index()
    {
         $res= Test1::with('method1')->get();
           return view('home' , compact(['res']));
    }
}

The tables are filled with test data, no more than 10 records… At the same time, through the debugger it shows 5 queries and 20 models… If you add records, the number of queries remains 5, and the number of models increases… Moreover, if there are about 1000 records, then There will be more than 10,000 models… Is it possible to optimize this somehow? How?

Upd

Here’s my blade

@foreach ($res as $result)
    <h2>{{ $result->name }}</h2>
    <ul>
        @foreach ($result->method1 as $res2)
            <li>
                <p>{{ $res2->name }}</p>
                <ul>
                    @foreach ($res2->method2 as $res3)
                        <li>
                            <p>{{ $res3->name }}</p>
                        </li>
                    @endforeach
                </ul>
            </li>
        @endforeach
    </ul>
@endforeach

Here is a screenshot of the debugger

enter image description here

2

Answers


  1. Let’s assume this users-posts-comments situation:

    To optimize the Laravel Eloquent query and avoid many model instances in the view, you can eager load the comments along with the posts and users. This will reduce the number of queries executed and improve the performance of your application.

    Here’s how you can modify your query and view:

    Query Optimization
    Load the comments along with the posts and users using eager loading:

    $users = User::with('posts.comments')->get();
    

    View Optimization
    You can directly access the comments through the posts that are already eager-loaded, avoiding the need for additional queries:

    @foreach($users as $user)
        @foreach($user->posts as $post)
            <h4>Comments from {{ $user->name }}</h4>
            @foreach($post->comments as $comment)
                <li>{{ $comment->comment }}</li>
            @endforeach
        @endforeach
    @endforeach
    

    This approach ensures that all the necessary data is fetched in a single query, reducing the load on your database and improving the performance of your application.

    Login or Signup to reply.
  2. The issue might be related to how you defined your relationships, I had a similar issue when I started programming because I just fetched all and Eloquent, for some reason, went into some circular motion and fetched some tables repeatedly because it had relationships with it..

    For this to work, update these migrations:

    // Test 2 table
    public function up(): void
    {
        Schema::create('test2s', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('desc')->nullable();
            $table->foreignId('test1_id')->constrained()->onDelete('cascade');
            $table->timestamps();
        });
    }
    

    test3 migration:

    // Test 3 table
    
    public function up(): void
    {
        Schema::create('test3s', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('desc')->nullable();
            $table->foreignId('test2_id')->constrained()->onDelete('cascade');
            $table->timestamps();
        });
    }
    

    then the models

    Test1 model:

    namespace AppModels;
    
    use IlluminateDatabaseEloquentFactoriesHasFactory;
    use IlluminateDatabaseEloquentModel;
    
    class Test1 extends Model
    {
        use HasFactory;
    
        public function test2s()
        {
            return $this->hasMany(Test2::class);
        }
    }
    

    Test 2 model:

    namespace AppModels;
    
    use IlluminateDatabaseEloquentFactoriesHasFactory;
    use IlluminateDatabaseEloquentModel;
    
    class Test2 extends Model
    {
        use HasFactory;
    
        public function test3s()
        {
            return $this->hasMany(Test3::class);
        }
    }
    

    Test 3 model:

    namespace AppModels;
    
    use IlluminateDatabaseEloquentFactoriesHasFactory;
    use IlluminateDatabaseEloquentModel;
    
    class Test3 extends Model
    {
        use HasFactory;
    
        // you can define inverse relationship also
    }
    

    Eager load the relationships without nesting so you reduce the number of queries:

    namespace AppHttpControllers;
    
    use AppModelsTest1;
    
    class HomeController extends Controller
    {
        public function index()
        {
            $res = Test1::with('test2s.test3s')->get();
            return view('home', compact('res'));
        }
    }
    

    and then! blade file update:

    @foreach ($res as $test1)
        <h2>{{ $test1->name }}</h2>
        <ul>
            @foreach ($test1->test2s as $test2)
                <li>
                    <p>{{ $test2->name }}</p>
                    <ul>
                        @foreach ($test2->test3s as $test3)
                            <li>
                                <p>{{ $test3->name }}</p>
                            </li>
                        @endforeach
                    </ul>
                </li>
            @endforeach
        </ul>
    @endforeach
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search