Tech Verse Logo
Enable dark mode
Managing MongoDB Transactions in Laravel: A Practical Guide

Managing MongoDB Transactions in Laravel: A Practical Guide

Tech Verse Daily

Tech Verse Daily

4 min read

MongoDB and Laravel are a powerful combination — Laravel gives you elegant structure, while MongoDB offers flexibility and scalability. But what happens when your operations depend on multiple collections that must update together — for example, a booking confirmation that updates both rooms and guests?

That’s where MongoDB transactions come in. In this article, we’ll explore how to use transactions in Laravel with MongoDB, how they work, and how to use them safely in real-world applications.

What Are Transactions and Why They Matter

A transaction groups multiple operations into one atomic unit — meaning all succeed or all fail.
If something goes wrong halfway through, the transaction rolls back and no partial data is saved.

For example, when a guest books a hotel room, you need to:

  1. Reserve the room.

  2. Create the booking record.

  3. Update the guest’s booking history.

If any of these fail, the others should roll back — otherwise you risk double-booking rooms or missing booking records.

MongoDB Transaction Support

MongoDB introduced multi-document transactions starting with version 4.0, bringing full ACID compliance (Atomicity, Consistency, Isolation, Durability) similar to relational databases.

To use transactions, you must run MongoDB as a replica set (even a single-node replica set works for development).

Laravel + MongoDB Setup

Install the Laravel MongoDB package:

composer require mongodb/laravel-mongodb

Then configure your database connection in config/database.php:

'mongodb' => [
    'driver'   => 'mongodb',
    'dsn'      => env('MONGODB_URI', 'mongodb://127.0.0.1:27017/?replicaSet=rs0'),
    'database' => env('MONGODB_DATABASE', 'hotel_booking_db'),
],

And in your .env:

DB_CONNECTION=mongodb
MONGODB_URI=mongodb://127.0.0.1:27017/?replicaSet=rs0
MONGODB_DATABASE=hotel_booking_db

Real-World Example: Hotel Booking Transaction

Let’s look at a scenario where you’re building a hotel booking system.
When a user books a room, three collections are affected:

  • rooms → mark the room as booked

  • bookings → insert a new booking record

  • guests → append the booking ID to the guest’s record

All of this must happen together — or not at all.

Here’s how you can do it in Laravel:

use Illuminate\Support\Facades\DB;
use MongoDB\BSON\ObjectId;

public function confirmBooking(string $roomId, string $guestId, string $checkIn, string $checkOut)
{
    $connection = DB::connection('mongodb');
    $client = $connection->getMongoClient();
    $db = $connection->getMongoDB();

    $session = $client->startSession();

    try {
        $session->startTransaction();

        $rooms = $db->selectCollection('rooms');
        $bookings = $db->selectCollection('bookings');
        $guests = $db->selectCollection('guests');

        // Check if room is available
        $room = $rooms->findOne(['_id' => new ObjectId($roomId), 'status' => 'available'], ['session' => $session]);

        if (! $room) {
            throw new \Exception('Room not available.');
        }

        // Mark room as booked
        $rooms->updateOne(
            ['_id' => new ObjectId($roomId)],
            ['$set' => ['status' => 'booked']],
            ['session' => $session]
        );

        // Create booking record
        $booking = [
            'room_id' => new ObjectId($roomId),
            'guest_id' => new ObjectId($guestId),
            'check_in' => $checkIn,
            'check_out' => $checkOut,
            'status' => 'confirmed',
            'created_at' => now(),
        ];
        $bookings->insertOne($booking, ['session' => $session]);

        // Add booking reference to guest record
        $guests->updateOne(
            ['_id' => new ObjectId($guestId)],
            ['$push' => ['bookings' => $booking]],
            ['session' => $session]
        );

        $session->commitTransaction();

        return response()->json(['message' => 'Booking confirmed successfully!']);
    } catch (\Exception $e) {
        $session->abortTransaction();
        return response()->json(['error' => $e->getMessage()], 500);
    }
}

If any operation fails, everything rolls back — ensuring data consistency.

Tips and Best Practices

  1. Use transactions only when needed
    MongoDB documents are atomic by default. If all your updates are within a single document, you don’t need a transaction.

  2. Keep transactions short
    The longer a transaction runs, the higher the chance of conflicts or timeouts.

  3. Always handle exceptions
    Wrap your code in try-catch blocks and make sure you commit or abort properly.

  4. Ensure you’re using a replica set
    Transactions won’t work in standalone MongoDB instances.

  5. Index frequently used fields
    Especially fields you use in lookups during transactions, like room_id or guest_id.

Reusable Transaction Service (Clean Code Example)

To keep your controllers clean, you can abstract transaction logic into a service class:

namespace App\Services;

use Illuminate\Support\Facades\DB;
use MongoDB\Client;

class MongoTransactionService
{
    public function run(callable $callback)
    {
        $client = DB::connection('mongodb')->getMongoClient();
        $session = $client->startSession();

        try {
            $session->startTransaction();
            $callback($session);
            $session->commitTransaction();
        } catch (\Throwable $e) {
            $session->abortTransaction();
            throw $e;
        }
    }
}

Usage:

app(MongoTransactionService::class)->run(function ($session) {
    // Your booking or cancellation logic here
});

Wrapping Up

MongoDB transactions give you the best of both worlds — flexibility of NoSQL and reliability of SQL-like atomic operations.

In Laravel, it’s straightforward to use them with the right setup. Whether you’re building an e-commerce platform, a hotel booking app, or any multi-step workflow, MongoDB transactions ensure your data stays consistent and reliable.

    Latest Posts

    View All

    React 19: What’s new in React 19

    React 19: What’s new in React 19

    Laravel Strict Validation: Enforcing Exact PHP Types

    Laravel Strict Validation: Enforcing Exact PHP Types

    Next.js 16.0.1: The Essential Update Developers Shouldn’t Skip

    Next.js 16.0.1: The Essential Update Developers Shouldn’t Skip

    Time Interval Helpers in Laravel 12.40

    Time Interval Helpers in Laravel 12.40

    From GitHub Actions to Production Rollout: CI/CD for Laravel

    From GitHub Actions to Production Rollout: CI/CD for Laravel

    Top React Libraries and Frameworks Every Frontend Developer Should Know

    Top React Libraries and Frameworks Every Frontend Developer Should Know

    PHP 8.5 New Features and Deprecations

    PHP 8.5 New Features and Deprecations

    Manage, Track and Monitor Queue Jobs in Laravel with Vantage

    Manage, Track and Monitor Queue Jobs in Laravel with Vantage

    Tinkerwell 5: Introducing Tinkerwell Intelligence

    Tinkerwell 5: Introducing Tinkerwell Intelligence

    Roach PHP - Complete Web Scraping toolkit for PHP

    Roach PHP - Complete Web Scraping toolkit for PHP