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

RiadhKHEDHIRI's avatar

Collection loosing relations and run into N+1 query problem in Livewire

Trivial example here, nothing crazy. I am loading posts with users info in mount. Everything works fine until I call createPost. What am I missing?

public function mount(): void
{
    $this->posts = Post::query()->orderBy('created_at', 'desc')->with('user')->take(10)->get();
}

public function createPost(): void
{
    $this->authorize('create', Post::class);
    $this->createPostForm->validate();

    $post = auth()->user()->posts()->create($this->createPostForm->only('body'));

    $this->createPostForm->reset();

    // This works
    // $this->posts = Post::query()->orderBy('created_at', 'desc')->with('user')->take(10)->get();
    
    // At this point, the collection items don't have the user relationship
    dd($this->posts);
    
    // Making this not work thus the N+1 query problem in Blade
    $this->posts->prepend($post);
}

Here is the Blade template:

<div class="mt-16 space-y-4">
    @foreach($this->posts as $post)
        <div wire:key="post-{{ $post->id }}">
            <a href="#" aria-label="Latest on our blog">
                <flux:card size="sm" class="hover:bg-zinc-50 dark:hover:bg-zinc-700">
                    <flux:heading class="flex items-center gap-2">{{ $post->body }}
                        <flux:icon name="arrow-up-right" class="ml-auto text-zinc-400" variant="micro"/>
                    </flux:heading>
                    <flux:text class="mt-2">{{ $post->user->name }} - {{ $post->created_at}}</flux:text>
                </flux:card>
            </a>
        </div>
    @endforeach
</div>
0 likes
5 replies
LaryAI's avatar

You're running into this issue because when you prepend the newly created $post to your $this->posts collection, that $post instance does not have its user relationship loaded. As a result, when you loop over $this->posts in your Blade view and access $post->user->name, Laravel will perform a query for each post that doesn't have the user relationship loaded, causing the N+1 problem.

Why does this happen?

  • In mount(), you eager load the user relationship:
    Post::query()->orderBy('created_at', 'desc')->with('user')->take(10)->get();
    
  • In createPost(), you create a new post, but the $post model returned from create() does not have the user relationship loaded.
  • When you prepend this $post to your $this->posts collection, only this new post is missing the relationship.

Solution

After creating the post, load its user relationship before prepending it to the collection.

Here's how you can do it:

public function createPost(): void
{
    $this->authorize('create', Post::class);
    $this->createPostForm->validate();

    $post = auth()->user()->posts()->create(
        $this->createPostForm->only('body')
    );

    $this->createPostForm->reset();

    // Eager load the user relationship on the new post
    $post->load('user');

    // Prepend the new post to the collection
    $this->posts->prepend($post);

    // Optionally, if you want to keep only the latest 10 posts:
    $this->posts = $this->posts->take(10);
}

Alternative: Always Reload the Collection

If you want to guarantee consistency (for example, if other users might create posts at the same time), you can always reload the collection after creating a post:

$this->posts = Post::query()
    ->orderBy('created_at', 'desc')
    ->with('user')
    ->take(10)
    ->get();

But for most cases, loading the relationship on the new post is sufficient and more efficient.


Summary:
Always ensure that any model you add to an eager-loaded collection also has the necessary relationships loaded. Use $post->load('user') before prepending.

Let me know if you need further clarification!

RiadhKHEDHIRI's avatar

@LaryAI

In the createPost() ALL the posts of the collection don't have the User relations, like they have been lost meanwhile somewhere after mount().

Please or to participate in this conversation.