EventGet 50% off your ticket to MongoDB.local London on October 2. Use code WEB50Learn more >>
MongoDB Developer
PHP
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
PHPchevron-right

How To Build a Laravel + MongoDB Back End Service

Hubert Nguyen15 min read • Published Aug 21, 2023 • Updated Aug 28, 2024
PHP
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Laravel is a leading PHP framework that vastly increases the productivity of PHP developers worldwide. I come from a WordPress background, but when asked to build a web service for a front end app, Laravel and MongoDB come to mind, especially when combined with the MongoDB Atlas developer data platform.
This Laravel MongoDB tutorial addresses prospective and existing Laravel developers considering using MongoDB as a database.
Let's create a simple REST back end for a front-end app and go over aspects of MongoDB that might be new. Using MongoDB doesn't affect the web front-end aspect of Laravel, so we'll use Laravel's built-in API routing in this article.
MongoDB support in Laravel is provided by the official mongodb/laravel-mongodb package, which extends Eloquent, Laravel's built-in ORM.
First, let's establish a baseline by creating a default Laravel app. We'll mirror some of the instructions provided on our MongoDB Laravel Integration page, which is the primary entry point for all things Laravel at MongoDB. Any Laravel environment should work, but we'll be using some Linux commands under Ubuntu in this article.

Prerequisites

Getting the Laravel web server up and running

Note: We'll go over creating the Laravel project with Composer but the article's code repository is available.
The "Setting Up and Configuring Your Laravel Project" instructions in the MongoDB and Laravel Integration show how to configure a Laravel-MongoDB development environment. We'll cover the Laravel application creation and the MongoDB configuration below.
Here are handy links, just in case: 

Create a Laravel project

With our development environment working, let's create a Laravel project by creating a Laravel project directory. From inside that new directory, create a new Laravel project called laraproject by running the command, which specifies using Laravel:
composer create-project laravel/laravel laraproject
After that, your directory structure should look like this:
Once our development environment is properly configured, we can browse to the Laravel site (likely 'localhost', for most people) and view the homepage:
The Laravel default homepage

Add a Laravel to MongoDB connection

Check if the MongoPHP driver is installed and running To check the MongoDB driver is up and running in our web server, we can add a webpage to our Laravel website. in the code project, open /routes/web.php and add a route as follows:
Subsequently visit the web page at localhost/info/ and we should see the PHPinfo page. Searching for the MongoDB section in the page, we should see something like the below. It means the MongoDB PHP driver is loaded and ready. If there are experience errors, our MongoDB PHP error handling goes over typical issues.
PHPinfo page, MongoDB section
We can use Composer to add the Laravel MongoDB package to the application. In the command prompt, go to the project's directory and run the command below to add the package to the <project>/vendor/ directory.
composer require mongodb/laravel-mongodb:4.0.0
Next, update the database configuration to add a MongoDB connection string and credentials. Open the /config/database.php file and update the 'connection' array as follows:
env('MONGODB_URI') refers to the content of the default .env file of the project. Make sure this file does not end up in the source control. Open the <project>/.env file and add the DB_URI environment variable with the connection string and credentials in the form:
MONGODB_URI=mongodb+srv://USERNAME:PASSWORD@clustername.subdomain.mongodb.net/?retryWrites=true&w=majority
Your connection string may look a bit different. Learn how to get the connection string in Atlas. Remember to allow the web server's IP address to access the MongoDB cluster. Most developers will add their current IP address to the cluster.
In /config/database.php, we can optionally set the default database connection. At the top of the file, change 'default' to this:
'default' => env('DB_CONNECTION', 'mongodb'),
Our Laravel application can connect to our MongoDB database. Let's create an API endpoint that pings it. In /routes/api.php, add the route below, save, and visit localhost/api/ping/. The API should return the object {"msg": "MongoDB is accessible!"}. If there's an error message, it's probably a configuration issue. Here are some general PHP MongoDB error handling tips.

Create data with Laravel's Eloquent 

Laravel comes with Eloquent, an ORM that abstracts the database back end so users can use different databases utilizing a common interface. Thanks to the Laravel MongoDB package, developers can opt for a MongoDB database to benefit from a flexible schema, excellent performance, and scalability.
Eloquent has a "Model" class, the interface between our code and a specific database table (or "collection," in MongoDB terminology). Instances of the Model classes represent rows of tables in relational databases.
In MongoDB, they are documents in the collection. In relational databases, we can set values only for columns defined in the database, but MongoDB allows any field to be set.
The models can define fillable fields if we want to enforce a document schema in our application and prevent errors like name typos. This is not required if we want full flexibility of being schemaless to be faster.
For new Laravel developers, there are many Eloquent features and philosophies. The official Eloquent documentation is the best place to learn more about that. For now, we will highlight the most important aspects of using MongoDB with Eloquent. We can use both MongoDB and an SQL database in the same Laravel application. Each model is associated with one connection or the other.

Classic Eloquent model

First, we create a classic model with its associated migration code by running the command:
php artisan make:model CustomerSQL --migration
After execution, the command created two files, <project>/app/Models/CustomerSQL.php and <project>/database/migrations/YY_MM_DD_xxxxxx_create_customer_s_q_l_s_table.php. The migration code is meant to be executed once in the prompt to initialize the table and schema. In the extended Migration class, check the code in the up() function.
We'll edit the migration's up() function to build a simple customer schema like this:
Our migration code is ready, so let's execute it to build the table and index associated with our Eloquent model.
php artisan migrate --path=/database/migrations/YY_MM_DD_xxxxxx_create_customer_s_q_l_s_table.php
In the MySQL database, the migration created a 'customer_sql' table with the required schema, along with the necessary indexes. Laravel keeps track of which migrations have been executed in the 'migrations' table.
A SQL database schema
Next, we can modify the model code in <project>/app/Models/CustomerSQL.php to match our schema.

MongoDB Eloquent model

Let's create an Eloquent model for our MongoDB database named "CustomerMongoDB" by running this Laravel prompt command from the project's directory"
php artisan make:model CustomerMongoDB
Laravel creates a CustomerMongoDB class in the file \models\CustomerMongoDB.php shown in the code block below. By default, models use the 'default' database connection, but we can specify which one to use by adding the $connection member to the class. Likewise, it is possible to specify the collection name via a $collection member.
Note how the base model class is replaced in the 'use' statement. This is necessary to set "_id" as the primary key and profit from MongoDB's advanced features like array push/pull.
The extended class definition is nearly identical to the default Laravel one. Note that $table is replaced by $collection to use MongoDB's naming. That's it.
We can still use Eloquent Migrations with MongoDB (more on that below), but defining the schema and creating a collection with a Laravel-MongoDB Migration is optional because of MongoDB's flexible schema. At a high level, each document in a MongoDB collection can have a different schema.
If we want to enforce a schema, we can! MongoDB has a great schema validation mechanism that works by providing a validation document when manually creating the collection using db.createcollection(). We'll cover this in an upcoming article.

CRUD with Eloquent

With the models ready, creating data for a MongoDB back end isn't different, and that's what we expect from an ORM.\
Below, we can compare the /api/create_eloquent_mongo/ and /api/create_eloquent_sql/ API endpoints. The code is identical, except for the different CustomerMongoDB and CustomerSQL model names.
After adding the document, we can retrieve it using Eloquent's "where" function as follows:
Eloquent allows developers to find data using complex queries with multiple matching conditions, and there's more to learn by studying both Eloquent and the MongoDB Laravel extension. The Laravel MongoDB query tests are an excellent place to look for additional syntax examples and will be kept up-to-date.
Of course, we can also Update and Delete records using Eloquent as shown in the code below:
Eloquent is an easy way to start with MongoDB, and things work very much like one would expect. Even with a simple schema, developers can benefit from great scalability, high data reliability, and cluster availability with MongoDB Atlas' fully-managed clusters and sharding.
At this point, our MongoDB-connected back-end service is up and running, and this could be the end of a typical "CRUD" article. However, MongoDB is capable of much more, so keep reading.

Unlock the full power of MongoDB

To extract the full power of MongoDB, it's best to fully utilize its document model and native Query API.
The document model is conceptually like a JSON object, but it is based on BSON (a binary representation with more fine-grained typing) and backed by a high-performance storage engine. Document supports complex BSON types, including object, arrays, and regular expressions. Its native Query API can efficiently access and process such data.

Why is the document model great?

Let's discuss a few benefits of the document model.

It reduces or eliminates joins

Embedded documents and arrays paired with data modeling allow developers to avoid expensive database "join" operations, especially on the most critical workloads, queries, and huge collections. If needed, MongoDB does support join-like operations with the $lookup operator, but the document model lets developers keep such operations to a minimum or get rid of them entirely. Reducing joins also makes it easier to shard collections across multiple servers to increase capacity.

It reduces workload costs

This NoSQL strategy is critical to increasing database workload efficiency, to reduce billing. That's why Amazon eliminated most of its internal relational database workloads years ago. Learn more by watching Rick Houlihan, who led this effort at Amazon, tell that story on YouTube, or read about it on our blog. He is now MongoDB's Field CTO for Strategic Accounts.

It helps avoid downtime during schema updates

MongoDB documents are contained within "collections" (tables, in SQL parlance). The big difference between SQL and MongoDB is that each document in a collection can have a different schema. We could store completely different schemas in the same collection. This enables strategies like schema versioning to avoid downtime during schema updates and more!
Data modeling goes beyond the scope of this article, but it is worth spending 15 minutes watching the Principles of Data Modeling for MongoDB video featuring Daniel Coupal, the author of MongoDB Data Modeling and Schema Design, a book that many of us at MongoDB have on our desks. At the very least, read this short 6 Rules of Thumb for MongoDB Schema article.

CRUD with nested data

The Laravel MongoDB Eloquent extension does offer MongoDB-specific operations for nested data. However, adding nested data is also very intuitive without using the embedsMany() and embedsOne() methods provided by the extension.
As shown earlier, it is easy to define the top-level schema attributes with Eloquent. However, it is more tricky to do so when using arrays and embedded documents.
Fortunately, we can intuitively create the Model's data structures in PHP. In the example below, the 'address' field has gone from a string to an object type. The 'email' field went from a string to an array [of strings] type. Arrays and objects are not supported types in MySQL.
If we run the localhost/api/create_nested/ API endpoint, it will create a document as the JSON representation below shows. The updated_at and created_at datetime fields are automatically added by Eloquent, and it is possible to disable this Eloquent feature (check the Timestamps in the official Laravel documentation).
JSON view of the newly added customer record

Introducing the MongoDB Query API

MongoDB has a native query API optimized to manipulate and transform complex data. There's also a powerful aggregation framework with which we can pipe data from one stage to another, making it intuitive for developers to create very complex aggregations. The native query is accessible via the MongoDB "collection" object.

Eloquent and "raw queries"

Eloquent has an intelligent way of exposing the full capabilities of the underlying database by using "raw queries," which are sent "as is" to the database without any processing from the Eloquent Query Builder, thus exposing the native query API. Read about raw expressions in the official Laravel documentation.
We can perform a raw native MongoDB query from the model as follows, and the model will return an Eloquent collection
It's also possible to obtain the native MongoDB collection object and perform a query that will return objects such as native MongoDB documents or cursors:
Using the MongoDB collection directly is the sure way to access all the MongoDB features. Typically, people start using the native collection.insert(), collection.find(), and collection.update() first.
Common MongoDB Query API functions work using a similar logic and require matching conditions to identify documents for selection or deletion. An optional projection defines which fields we want in the results.
With Laravel, there are several ways to query data, and the /find_native/ API endpoint below shows how to use whereRaw(). Additionally, we can use MongoDB's findOne() and find() collection methods that return a document and a cursor, respectively.
Updating documents is done by providing a list of updates in addition to the matching criteria. Here's an example using updateOne(), but updateMany() works similarly. updateOne() returns a document that contains information about how many documents were matched and how many were actually modified.
Deleting documents is as easy as finding them. Again, there's a matching criterion, and the API returns a document indicating the number of deleted documents.

Aggregation pipeline

Since we now have access to the MongoDB native API, let's introduce the aggregation pipeline. An aggregation pipeline is a task in MongoDB's aggregation framework. Developers use the aggregation framework to perform various tasks, from real-time dashboards to "big data" analysis.
We will likely use it to query, filter, and sort data at first. The aggregations introduction of the free online book Practical MongoDB Aggregations by Paul Done gives a good overview of what can be done with it.
An aggregation pipeline consists of multiple stages where the output of each stage is the input of the next, like piping in Unix.
We will use the "sample_mflix" sample database that should have been loaded when creating our Atlas cluster. Laravel lets us access multiple MongoDB databases in the same app, so let's add the sample_mflix database (to database.php):
Next, we can build an /aggregate/ API endpoint and define a three-stage aggregation pipeline to fetch data from the "movies" collection, compute the average movie rating per genre, and return a list. More details about this movie ratings aggregation.
This shows how easy it is to compose several stages to group, compute, transform, and sort data. This is the preferred method to perform aggregation operations, and it's even possible to output a document, which is subsequently used by the updateOne() method. There's a whole aggregation course.

Don't forget to index

We now know how to perform CRUD operations, native queries, and aggregations. However, don't forget about indexing to increase performance. MongoDB indexing strategies and best practices are beyond the scope of this article, but let's look at how we can create indexes.

Option #1: Create indexes with Eloquent's Migrations

First, we can use Eloquent's Migrations. Even though we could do without Migrations because we have a flexible schema, they could be a vessel to store how indexes are defined and created.
Since we have not used the --migration option when creating the model, we can always create the migration later. In this case, we can run this command:
php artisan make:migration create_customer_mongo_db_table
It will create a Migration located at <project>/database/migrations/YYYY_MM_DD_xxxxxx_create_customer_mongo_db_table.php.
We can update the code of our up() function to create an index for our collection. For example, we'll create an index for our 'guid' field, and make it a unique constraint. By default, MongoDB always has an _id primary key field initialized with an ObjectId by default. We can provide our own unique identifier in place of MongoDB's default ObjectId.
As previously, this migration up() function can be executed using the command:
php artisan migrate --path=/database/migrations/2023_08_09_051124_create_customer_mongo_db_table.php
If the 'laracoll' collection does not exist, it is created and an index is created for the 'guid' field. In the Atlas GUI, it looks like this:
guid_1 index listed in MongoDB Atlas

Option #2: Create indexes with MongoDB's native API

The second option is to use the native MongoDB createIndex() function which might have new options not yet covered by the Laravel MongoDB package. Here's a simple example that creates an index with the 'guid' field as the unique constraint.

Option #3: Create indexes with the Atlas GUI

Finally, we can also create an Index in the web Atlas GUI interface, using a visual builder or from JSON. The GUI interface is handy for experimenting. The same is true inside MongoDB Compass, our MongoDB GUI application.
Index creation from the MongoDB Atlas GUI

Conclusion

This article covered creating a back-end service with PHP/Laravel, powered by MongoDB, for a front-end web application. We've seen how easy it is for Laravel developers to leverage their existing skills with a MongoDB back end.
It also showed why the document model, associated with good data modeling, leads to higher database efficiency and scalability. We can fully use it with the native MongoDB Query API to unlock the full power of MongoDB to create better apps with less downtime.
Learn more about the Laravel MongoDB extension syntax by looking at the official documentation and repo's example tests on GitHub. For plain PHP MongoDB examples, look at the example tests of our PHP Library.
Consider taking the free Data Modeling course at MongoDB University or the overall PHP/MongoDB course, although it's not specific to Laravel.
We will build more PHP/Laravel content, so subscribe to our various channels, including YouTube and LinkedIn. Finally, join our official community forums! There's a PHP tag where fellow developers and MongoDB engineers discuss all things data and PHP.

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
News & Announcements

MongoDB PHP Extension 1.13.0 Released


May 24, 2022 | 1 min read
Code Example

Introducing the Tour Planner With MongoDB Vector Search


Sep 24, 2024 | 5 min read
News & Announcements

Laravel MongoDB 5.0: Major Release With Exciting New Features!


Sep 13, 2024 | 1 min read
Quickstart

Complex Aggregation Pipelines with Vanilla PHP and MongoDB


Sep 05, 2024 | 10 min read
Table of Contents