Laravel relationships attach if not already attached

Using syncWithoutDetaching or sync([arr], false) looks cleaner in code, but performs 25x slower than attach(). This is because it checks each id and performs individual database inserts per item.

I'd suggest building upon Paul Spiegel's answer by extending eloquent or creating a new method on your model class.

In my use case I have a Feed class and a Post class linked by a many to many pivot. I added the following method to my Feed class.

public function attachUniquePosts($ids)
{
    $existing_ids = $this->posts()->whereIn('posts.id', $ids)->pluck('posts.id');
    $this->posts()->attach($ids->diff($existing_ids));
}
  • Attaching 20 posts to a feed using syncWithoutDetaching() took on average 0.107s
  • Attaching 20 posts to a feed using attachUniquePosts() took on average 0.004s

Laravel has built-in method for this - syncWithoutDetaching:

$message->Users()->syncWithoutDetaching($request->get('users'));