<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ MongoDB - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ MongoDB - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 11 May 2026 22:40:03 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/mongodb/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Build a Full Stack Movie Streaming App with Go, React, MongoDB, OpenAI ]]>
                </title>
                <description>
                    <![CDATA[ We’ve just posted a full-stack course on the freeCodeCamp.org YouTube channel that will teach you to build a complete, production-ready movie streaming application named MagicStream, complete with AI-powered movie recommendations. This course is desi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-full-stack-movie-streaming-app-with-go-react-mongodb-openai/</link>
                <guid isPermaLink="false">68dd9632756047816483e15e</guid>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 01 Oct 2025 20:59:30 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759352344795/21e9357b-d611-4223-a1f3-704960eae165.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>We’ve just posted a full-stack course on the <a target="_blank" href="http://freeCodeCamp.org">freeCodeCamp.org</a> YouTube channel that will teach you to build a complete, production-ready movie streaming application named MagicStream, complete with AI-powered movie recommendations. This course is designed to give you a deep, practical understanding of a modern, powerful tech stack. Gavin Lon teaches this course.</p>
<p>The foundation of this project is built on high-performance technologies. On the backend, the course uses Go (Golang) paired with the lightning-fast Gin-Gonic framework to create a robust and efficient Web API. This combination is fantastic for handling concurrent requests, making the application quick and reliable. For the frontend, you'll be building a responsive and engaging user interface using React. All your data, from user profiles to movie details, will be stored in MongoDB, offering flexible and scalable data management. This combination of Go, React, and MongoDB provides a well-rounded and impressive skillset for any full-stack developer.</p>
<p>You'll learn to connect your Go backend directly to OpenAI’s models using the power of the LangChainGo library. This connection allows you to build a genuine, intelligent service that can analyze data and provide personalized movie suggestions. Also, you'll implement secure user authentication, including registration, login, and access token validation via middleware. Security is a priority, so the course even covers the best practice of storing access tokens in http-only cookies to prevent Cross-Site Scripting (XSS) attacks.</p>
<p>Once the core features are built and working, you’ll will learn to deploy the applicaiton. You’ll get hands-on experience taking your database live by deploying MongoDB to Atlas, hosting your Go/Gin-Gonic API on Render, and deploying the React client to Vercel.</p>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/jBf7of9JTV8">the freeCodeCamp.org YouTube channel</a> (15-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/jBf7of9JTV8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Build Secure Web Applications with PHP, Symfony, and MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ Data breaches are a constant threat, and traditional encryption practices often aren't enough to protect sensitive information throughout its entire lifecycle. We just posted a course on the freeCodeCamp.org YouTube channel that will teach you how to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-secure-web-applications-with-php-symfony-and-mongodb/</link>
                <guid isPermaLink="false">68c2cf0fe8903924be3e8c8c</guid>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Symfony ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 11 Sep 2025 13:30:55 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757573041841/0bbcb80c-76b9-4792-be3b-fba79ea344b1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Data breaches are a constant threat, and traditional encryption practices often aren't enough to protect sensitive information throughout its entire lifecycle.</p>
<p>We just posted a course on the freeCodeCamp.org YouTube channel that will teach you how to build applications that are truly secure from the ground up using PHP, Symfony, and MongoDB.</p>
<p>I developed this course. I will teach you how to build a system where data is protected not just at rest and in transit, but also while it's in use.</p>
<p>Throughout this comprehensive, step-by-step tutorial, you will build a fully functional personal finance application. The application will allow users to create accounts, log transactions, and view their financial information.</p>
<p>The core of this course focuses on solving a major challenge in application security which is how to perform queries on encrypted data. You'll learn how to find a user by their social security number or search for transactions within a specific amount range, all without ever decrypting the information on the database server.</p>
<p>I use MongoDB's Queryable Encryption to encrypt sensitive data on the client-side. This data is then stored as fully randomized encrypted fields in the database, yet you can still run equality and range-check queries on it. The server never has access to the unencrypted data or the encryption keys, keeping the data secure throughout its entire life cycle.</p>
<p>This tutorial is designed for developers who have some experience with PHP and a framework like Symfony or Laravel, but even if you're new to these technologies, you should be able to follow along.</p>
<p>Watch the full course now <a target="_blank" href="https://youtu.be/UuknxVdqzb4">on the freeCodeCamp.org YouTube channel</a> (1-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/UuknxVdqzb4" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Building an AI-Powered E-commerce Chat Assistant with MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ Chatbots should do more than just chat. We just published a new course on the freeCodeCamp.org YouTube channel that will teach you how to build a smart AI shopping assistant from the ground up. This comprehensive course, created by Ania Kubow, goes b... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/building-an-ai-powered-e-commerce-chat-assistant-with-mongodb/</link>
                <guid isPermaLink="false">68a5d65a03d81d59ec026535</guid>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                    <category>
                        <![CDATA[ llm ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 20 Aug 2025 14:06:18 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755696350459/cb15e21b-789c-4107-b7f2-dc12d0df7d79.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Chatbots should do more than just chat.</p>
<p>We just published a new course on the <a target="_blank" href="http://freeCodeCamp.org">freeCodeCamp.org</a> YouTube channel that will teach you how to build a smart AI shopping assistant from the ground up.</p>
<p>This comprehensive course, created by Ania Kubow, goes beyond typical chatbot tutorials. You will create a powerful AI agent that thinks and acts like a real sales associate, capable of making its own decisions to help customers.</p>
<p>This AI agent can:</p>
<ul>
<li><p>Autonomously decide when to search a database versus when to respond directly.</p>
</li>
<li><p>Use custom tools to search through real product information.</p>
</li>
<li><p>Remember past parts of the conversation.</p>
</li>
<li><p>Take multi-step actions to perceive, plan, act, and respond to a customer.</p>
</li>
</ul>
<p>Throughout the course, you will work with modern, cutting-edge technologies. You'll use LangGraph for agent orchestration, MongoDB Atlas for vector search and memory, and Google's Gemini to power the AI's brain. Ania explains everything step-by-step, so you don't need to be an expert in these tools to get started.</p>
<p>By the time you finish, you will have built a complete project with three parts: a Node.js backend, a MongoDB database with AI-generated product data, and a user-friendly React frontend.</p>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/9tANiA0LKn4">the freeCodeCamp.org YouTube channel</a> (2-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/9tANiA0LKn4" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use MongoDB with Go ]]>
                </title>
                <description>
                    <![CDATA[ Working with databases is a fundamental part of backend development, particularly when you’re building applications that require persisting, querying, and updating data. In Go, the official MongoDB driver provides a robust way to connect to and inter... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-mongodb-with-go/</link>
                <guid isPermaLink="false">688b03e7d853646bf4658392</guid>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwadamilola Oshungboye ]]>
                </dc:creator>
                <pubDate>Thu, 31 Jul 2025 05:49:27 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753940956019/6551a007-b463-486f-8746-15c13a7a99a0.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Working with databases is a fundamental part of backend development, particularly when you’re building applications that require persisting, querying, and updating data.</p>
<p>In Go, the <a target="_blank" href="https://github.com/mongodb/mongo-go-driver">official MongoDB driver</a> provides a robust way to connect to and interact with MongoDB, a flexible NoSQL database that stores data in JSON-like documents.</p>
<p>In this tutorial, you won't just learn how to connect Go to MongoDB. You'll take it a step further by building a simple blog application. Along the way, you'll learn how to perform essential CRUD (Create, Read, Update, Delete) operations and display your results using the Gin web framework.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-a-new-go-project">Create a New Go Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-basic-mongodb-operations">Basic MongoDB Operations</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-insert-data-into-the-collection">Insert data into the collection</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-find-documents-in-mongodb">Find documents in MongoDB</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-update-documents-in-mongodb">Update documents in MongoDB</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-delete-documents-in-mongodb">Delete documents in MongoDB</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-a-blog-app-with-go-mongodb-driver-and-gin">How to Build a Blog App with go-mongodb-driver and Gin</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-initialize-the-gin-application">Initialize the Gin application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-the-html-templates">Create the HTML templates</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-the-handlers">Create the handlers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-run-the-application">Run the application</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-thats-how-to-use-mongodb-with-go">That's How to Use MongoDB with Go</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you proceed, ensure that you have the following:</p>
<ul>
<li><p>Basic knowledge of <a target="_blank" href="https://go.dev/">Go</a> and its concepts</p>
</li>
<li><p>Go (version 1.24 or higher) installed</p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/docs/manual/installation/">MongoDB</a> Installed (running locally on port 27017)</p>
</li>
<li><p>Basic knowledge of NoSQL</p>
</li>
</ul>
<h2 id="heading-create-a-new-go-project">Create a New Go Project</h2>
<p>First, create a new Go project, change into the new project directory, and initialize a new Go module by running the following commands:</p>
<pre><code class="lang-bash">mkdir go-mongodb-integration
<span class="hljs-built_in">cd</span> go-mongodb-integrationgo 
mod init go-mongodb
</code></pre>
<p>Next, install the MongoDB Go driver by running the following command:</p>
<pre><code class="lang-bash">go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/bson
</code></pre>
<p>The standard Go library includes the <code>database/sql</code> package for working with SQL databases, but it doesn't support MongoDB out of the box. To work with MongoDB in Go, you’ll use the official MongoDB driver, which provides everything you need to connect to and interact with a MongoDB database.</p>
<p>With the basic setup complete, let’s now examine basic operations in MongoDB.</p>
<h2 id="heading-basic-mongodb-operations">Basic MongoDB Operations</h2>
<p>In MongoDB, databases and <a target="_blank" href="https://www.mongodb.com/docs/manual/reference/glossary/#std-term-collection">collections</a> are created automatically upon the first data insertion, adopting a "lazy creation" approach. Specifically, a database is created when you insert your first document, and a collection is likewise created when data is first inserted into it.</p>
<p>It's important to note that functions like <code>client.Database()</code> and <code>db.Collection()</code> only generate references to these structures – they don’t create the actual database or collection until data is inserted.</p>
<h3 id="heading-insert-data-into-the-collection">Insert data into the collection</h3>
<p>Let’s walk through how to insert a document into a collection in MongoDB.</p>
<p>First, open your project in a code editor, create a <code>main.go</code> file, and add the following code:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)

<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    ID   primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty"`</span>
    Name <span class="hljs-keyword">string</span>             <span class="hljs-string">`bson:"name"`</span>
    Age  <span class="hljs-keyword">int</span>                <span class="hljs-string">`bson:"age"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)

    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    client, err := mongo.Connect(ctx, clientOptions)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    <span class="hljs-keyword">defer</span> client.Disconnect(ctx)

    err = client.Ping(ctx, <span class="hljs-literal">nil</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }

    db := client.Database(<span class="hljs-string">"test_db"</span>)
    usersCollection := db.Collection(<span class="hljs-string">"users"</span>)

    newUser := User{
        Name: <span class="hljs-string">"John Doe"</span>,
        Age:  <span class="hljs-number">30</span>,
    }

    result, err := usersCollection.InsertOne(ctx, newUser)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }

    log.Printf(<span class="hljs-string">"Inserted user with ID: %v\n"</span>, result.InsertedID)
}
</code></pre>
<p>In the code above, you define a <code>User</code> <a target="_blank" href="https://www.w3schools.com/go/go_struct.php">struct</a> that represents your document structure, then insert a new user document into the collection using the <code>InsertOne</code> method. When you run this insert operation, MongoDB automatically creates both the <code>test_db</code> database and the <code>users</code> collection if they don’t already exist.</p>
<p>Execute the code by running:</p>
<pre><code class="lang-bash">go run main.go
</code></pre>
<p>You should see the response below, indicating that a user was inserted successfully.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753561045916/79c1f4f1-ebe1-41e8-b6dd-01a5e2c9d247.png" alt="A command line interface showing the command `go run main.go` with an output that says, &quot;Inserted user with ID: ObjectID('6862f3112341b0492801633b')&quot; on June 30, 2025." class="image--center mx-auto" width="1068" height="130" loading="lazy"></p>
<h3 id="heading-find-documents-in-mongodb">Find documents in MongoDB</h3>
<p>Now that you've inserted some data, it's time to query the database and retrieve documents.</p>
<p>Update your <code>main.go</code> file with the following code:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)

<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    ID   primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty"`</span>
    Name <span class="hljs-keyword">string</span>             <span class="hljs-string">`bson:"name"`</span>
    Age  <span class="hljs-keyword">int</span>                <span class="hljs-string">`bson:"age"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)

    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    client, err := mongo.Connect(ctx, clientOptions)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    <span class="hljs-keyword">defer</span> client.Disconnect(ctx)

    db := client.Database(<span class="hljs-string">"test_db"</span>)
    usersCollection := db.Collection(<span class="hljs-string">"users"</span>)

    cursor, err := usersCollection.Find(ctx, bson.M{})
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    <span class="hljs-keyword">defer</span> cursor.Close(ctx)

    <span class="hljs-keyword">var</span> users []User
    <span class="hljs-keyword">if</span> err = cursor.All(ctx, &amp;users); err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }

    <span class="hljs-keyword">for</span> _, user := <span class="hljs-keyword">range</span> users {
        fmt.Printf(<span class="hljs-string">"User: %s, Age: %d, ID: %s\n"</span>, user.Name, user.Age, user.ID.Hex())
    }
}
</code></pre>
<p>In the code above, you use the <code>Find</code> method with an empty filter (`bson.M{}`) to retrieve all documents from the <code>users</code> collection. Then, you use <code>cursor.All</code> to decode all the results into a slice of <code>User</code> structs.</p>
<p>Each document is printed to the terminal, showing the name, age, and ID of every user in the collection.</p>
<p>To run the code, use:</p>
<pre><code class="lang-bash">go run main.go
</code></pre>
<p>You should see the response below in your terminal.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753561158932/adc32e01-742e-4c5c-acf8-a83e1197a27c.png" alt="Screenshot of a terminal showing a Go command execution and output with user information including name, age, and ID." width="512" height="83" loading="lazy"></p>
<h3 id="heading-update-documents-in-mongodb">Update documents in MongoDB</h3>
<p>To update a document in your collection, modify your <code>main.go</code> file as shown below:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)

<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    ID   primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty"`</span>
    Name <span class="hljs-keyword">string</span>             <span class="hljs-string">`bson:"name"`</span>
    Age  <span class="hljs-keyword">int</span>                <span class="hljs-string">`bson:"age"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)
    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    client, err := mongo.Connect(ctx, clientOptions)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    <span class="hljs-keyword">defer</span> client.Disconnect(ctx)

    db := client.Database(<span class="hljs-string">"test_db"</span>)
    usersCollection := db.Collection(<span class="hljs-string">"users"</span>)

    <span class="hljs-keyword">var</span> userToUpdate User
    err = usersCollection.FindOne(ctx, bson.M{<span class="hljs-string">"name"</span>: <span class="hljs-string">"John Doe"</span>}).Decode(&amp;userToUpdate)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Println(<span class="hljs-string">"No user found to update"</span>)
    } <span class="hljs-keyword">else</span> {
        update := bson.M{
            <span class="hljs-string">"$set"</span>: bson.M{
                <span class="hljs-string">"name"</span>: <span class="hljs-string">"Jane Doe"</span>,
                <span class="hljs-string">"age"</span>:  <span class="hljs-number">25</span>,
            },
        }
        result, err := usersCollection.UpdateOne(
            ctx,
            bson.M{<span class="hljs-string">"_id"</span>: userToUpdate.ID},
            update,
        )
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            log.Fatal(err)
        }
        log.Printf(<span class="hljs-string">"Updated %v document(s)\n"</span>, result.ModifiedCount)
    }
}
</code></pre>
<p>In the code above, you first search for a user named "John Doe" using the <code>FindOne</code> method. If a match is found, you use the <code>UpdateOne</code> method to update their name and age. The <code>$set</code> operator ensures that only the specified fields are updated, leaving the rest of the document unchanged.</p>
<p>Execute the code by running:</p>
<pre><code class="lang-bash">go run main.go
</code></pre>
<p>You should see output in your terminal indicating how many documents were updated.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753561280040/73f7a859-5d7a-440a-a58b-b6105b8837ab.png" alt="Command line interface showing &quot;go run main.go&quot; and the output &quot;2025/06/30 21:34:36 Updated 1 document(s)&quot;." width="512" height="89" loading="lazy"></p>
<h3 id="heading-delete-documents-in-mongodb">Delete documents in MongoDB</h3>
<p>To remove documents from a collection, you can use the <code>DeleteOne</code> method. Update your <code>main.go</code> file with the following code:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)

<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    ID   primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty"`</span>
    Name <span class="hljs-keyword">string</span>             <span class="hljs-string">`bson:"name"`</span>
    Age  <span class="hljs-keyword">int</span>                <span class="hljs-string">`bson:"age"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)
    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    client, err := mongo.Connect(ctx, clientOptions)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    <span class="hljs-keyword">defer</span> client.Disconnect(ctx)

    db := client.Database(<span class="hljs-string">"test_db"</span>)
    usersCollection := db.Collection(<span class="hljs-string">"users"</span>)

    result, err := usersCollection.DeleteOne(ctx, bson.M{<span class="hljs-string">"name"</span>: <span class="hljs-string">"Jane Doe"</span>})
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    log.Printf(<span class="hljs-string">"Deleted %v document(s)\n"</span>, result.DeletedCount)
}
</code></pre>
<p>In the code above, you use the <code>DeleteOne</code> method to remove the first document that matches the filter <code>{ "name": "Jane Doe" }</code>.</p>
<p>You should see the result below in your terminal.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753561355070/ab8797ef-8a15-47e0-8502-9b120fbbd2b8.png" alt="A command line terminal showing the execution of &quot;go run main.go&quot; and outputting &quot;2025/06/30 21:36:05 Deleted 1 document(s)&quot;." width="512" height="84" loading="lazy"></p>
<h2 id="heading-how-to-build-a-blog-app-with-go-mongodb-driver-and-gin">How to Build a Blog App with go-mongodb-driver and Gin</h2>
<p>Now that you understand how to perform basic CRUD operations with MongoDB in Go, you're ready to build a more complete application.</p>
<p>Start by creating a new directory for your project and initializing it as a Go module. Navigate to your chosen directory and run:</p>
<pre><code class="lang-bash">mkdir go-blog
<span class="hljs-built_in">cd</span> go-blog
go mod init blog
</code></pre>
<p>Next, install the required dependencies:</p>
<pre><code class="lang-bash">go get github.com/gin-gonic/gin
go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/bson
</code></pre>
<p>Your project will have the following structure:</p>
<pre><code class="lang-bash">go-blog/  
├── main.go  
├── handlers/  
│   └── main.go  
└── templates/  
    ├── index.html  
    ├── post.html  
    ├── create.html  
    └── edit.html
</code></pre>
<h3 id="heading-initialize-the-gin-application">Initialize the Gin application</h3>
<p>To initialize a new Gin application, create a new <code>main.go</code> file and add the below code snippet to it:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"blog/handlers"</span>

    <span class="hljs-string">"github.com/gin-gonic/gin"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo/options"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">10</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    clientOptions := options.Client().ApplyURI(<span class="hljs-string">"mongodb://localhost:27017"</span>)
    client, err := mongo.Connect(ctx, clientOptions)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    <span class="hljs-keyword">defer</span> client.Disconnect(ctx)

    err = client.Ping(ctx, <span class="hljs-literal">nil</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
    log.Println(<span class="hljs-string">"Connected to MongoDB!"</span>)

    db := client.Database(<span class="hljs-string">"blog_db"</span>)
    h := handlers.NewHandler(db)

    router := gin.Default()
    router.LoadHTMLGlob(<span class="hljs-string">"templates/*"</span>)

    router.GET(<span class="hljs-string">"/"</span>, h.HomePage)
    router.GET(<span class="hljs-string">"/post/:id"</span>, h.ViewPost)
    router.GET(<span class="hljs-string">"/create"</span>, h.CreatePost)
    router.GET(<span class="hljs-string">"/edit/:id"</span>, h.EditPost)
    router.POST(<span class="hljs-string">"/save"</span>, h.SavePost)
    router.GET(<span class="hljs-string">"/delete/:id"</span>, h.DeletePost)

    log.Println(<span class="hljs-string">"Server starting on :8080..."</span>)
    router.Run(<span class="hljs-string">":8080"</span>)
}
</code></pre>
<p>The code above sets up the MongoDB connection, initializes the Gin router, and registers your routes.</p>
<h3 id="heading-create-the-html-templates">Create the HTML templates</h3>
<p>Now, create the HTML templates for displaying the blog UI.</p>
<p>First, create a <code>templates</code> directory and add the following files:</p>
<h4 id="heading-indexhtml">index.html:</h4>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Go Blog with MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100 min-h-screen"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mx-auto px-4 py-8"</span>&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-8"</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold text-center text-blue-600"</span>&gt;</span>Go Blog with MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-center mt-4"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/create"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"</span>&gt;</span>Create New Post<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"</span>&gt;</span>  
            {{range .}}  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-6"</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-xl font-semibold mb-2 text-gray-800"</span>&gt;</span>{{.Title}}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600 mb-4 line-clamp-3"</span>&gt;</span>  
                        {{if gt (len .Content) 150}}  
                            {{slice .Content 0 150}}...  
                        {{else}}  
                            {{.Content}}  
                        {{end}}  
                    <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-between items-center text-sm text-gray-500"</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{{.CreatedAt.Format "Jan 02, 2006"}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/post/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-500 hover:text-blue-700"</span>&gt;</span>Read More<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex border-t border-gray-200"</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/edit/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-1/2 py-2 text-center text-sm text-gray-600 hover:bg-gray-100 border-r border-gray-200"</span>&gt;</span>Edit<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/delete/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-1/2 py-2 text-center text-sm text-red-600 hover:bg-gray-100"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"return confirm('Are you sure you want to delete this post?')"</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
            {{else}}  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-span-3 text-center py-12"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600 text-lg"</span>&gt;</span>No posts yet. <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/create"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-blue-500 hover:underline"</span>&gt;</span>Create one<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
            {{end}}  
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This template lists all blog posts and includes buttons to create, edit, or delete posts.</p>
<h4 id="heading-posthtml">post.html:</h4>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>{{.Title}} | Go Blog with MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100 min-h-screen"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mx-auto px-4 py-8"</span>&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-8"</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold text-center text-blue-600"</span>&gt;</span>Go Blog with MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-center mt-4"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"</span>&gt;</span>Back to Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"max-w-3xl mx-auto bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-6"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-2xl font-bold mb-4 text-gray-800"</span>&gt;</span>{{.Title}}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>  

                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-center text-sm text-gray-500 mb-6"</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Posted: {{.CreatedAt.Format "Jan 02, 2006"}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>  
                    {{if ne .CreatedAt .UpdatedAt}}  
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mx-2"</span>&gt;</span>•<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Updated: {{.UpdatedAt.Format "Jan 02, 2006"}}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>  
                    {{end}}  
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  

                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"prose max-w-none"</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-700 whitespace-pre-line"</span>&gt;</span>{{.Content}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>  
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  

            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex border-t border-gray-200"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/edit/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-1/2 py-3 text-center text-blue-600 hover:bg-gray-100 border-r border-gray-200"</span>&gt;</span>Edit Post<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/delete/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-1/2 py-3 text-center text-red-600 hover:bg-gray-100"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"return confirm('Are you sure you want to delete this post?')"</span>&gt;</span>Delete Post<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This template displays a single post.</p>
<h4 id="heading-createhtml">create.html:</h4>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Create New Post | Go Blog with MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100 min-h-screen"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mx-auto px-4 py-8"</span>&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-8"</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold text-center text-blue-600"</span>&gt;</span>Go Blog with MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-center mt-4"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"</span>&gt;</span>Back to Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"max-w-2xl mx-auto bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-6"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-2xl font-bold mb-6 text-gray-800"</span>&gt;</span>Create New Post<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>  

                <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/save"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"block text-gray-700 font-medium mb-2"</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">required</span>  
                            <span class="hljs-attr">class</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"</span>&gt;</span>  
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  

                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"block text-gray-700 font-medium mb-2"</span>&gt;</span>Content<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">required</span>  
                            <span class="hljs-attr">class</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>  
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  

                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-end"</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-md"</span>&gt;</span>  
                            Save Post  
                        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>  
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
                <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This template allows you to create a new post.</p>
<h4 id="heading-edithtml">edit.html:</h4>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Edit Post | Go Blog with MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-gray-100 min-h-screen"</span>&gt;</span>  
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container mx-auto px-4 py-8"</span>&gt;</span>  
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-8"</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-3xl font-bold text-center text-blue-600"</span>&gt;</span>Go Blog with MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-center mt-4"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"</span>&gt;</span>Back to Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"max-w-2xl mx-auto bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>  
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-6"</span>&gt;</span>  
                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-2xl font-bold mb-6 text-gray-800"</span>&gt;</span>Edit Post<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>  

                <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/save"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span>&gt;</span>  
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"id"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"{{.ID.Hex}}"</span>&gt;</span>  

                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"block text-gray-700 font-medium mb-2"</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"{{.Title}}"</span> <span class="hljs-attr">required</span>  
                            <span class="hljs-attr">class</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"</span>&gt;</span>  
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  

                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"block text-gray-700 font-medium mb-2"</span>&gt;</span>Content<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"content"</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">required</span>  
                            <span class="hljs-attr">class</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"</span>&gt;</span>{{.Content}}<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>  
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  

                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex justify-between"</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/post/{{.ID.Hex}}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-gray-600 hover:text-gray-800"</span>&gt;</span>Cancel<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>  
                        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-md"</span>&gt;</span>  
                            Update Post  
                        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>  
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
                <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>  
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>  
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This template is used to edit a post.</p>
<h3 id="heading-create-the-handlers">Create the handlers</h3>
<p>Next, set up the handlers to connect with MongoDB and render the templates. Create a new folder called <code>handlers</code> in your project's root directory, then add a <code>main.go</code> file inside it and insert the following code snippet:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> handlers

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"net/http"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"github.com/gin-gonic/gin"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/bson/primitive"</span>
    <span class="hljs-string">"go.mongodb.org/mongo-driver/mongo"</span>
)

<span class="hljs-keyword">type</span> Post <span class="hljs-keyword">struct</span> {
    ID        primitive.ObjectID <span class="hljs-string">`bson:"_id,omitempty" json:"id"`</span>
    Title     <span class="hljs-keyword">string</span>             <span class="hljs-string">`bson:"title" json:"title"`</span>
    Content   <span class="hljs-keyword">string</span>             <span class="hljs-string">`bson:"content" json:"content"`</span>
    CreatedAt time.Time          <span class="hljs-string">`bson:"created_at" json:"created_at"`</span>
    UpdatedAt time.Time          <span class="hljs-string">`bson:"updated_at" json:"updated_at"`</span>
}

<span class="hljs-keyword">type</span> Handler <span class="hljs-keyword">struct</span> {
    db         *mongo.Database
    collection *mongo.Collection
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewHandler</span><span class="hljs-params">(db *mongo.Database)</span> *<span class="hljs-title">Handler</span></span> {
    <span class="hljs-keyword">return</span> &amp;Handler{
        db:         db,
        collection: db.Collection(<span class="hljs-string">"posts"</span>),
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">HomePage</span><span class="hljs-params">(c *gin.Context)</span></span> {
    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    cursor, err := h.collection.Find(ctx, bson.M{})
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
        <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">defer</span> cursor.Close(ctx)

    <span class="hljs-keyword">var</span> posts []Post
    <span class="hljs-keyword">if</span> err = cursor.All(ctx, &amp;posts); err != <span class="hljs-literal">nil</span> {
        c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
        <span class="hljs-keyword">return</span>
    }

    c.HTML(http.StatusOK, <span class="hljs-string">"index.html"</span>, posts)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">ViewPost</span><span class="hljs-params">(c *gin.Context)</span></span> {
    id := c.Param(<span class="hljs-string">"id"</span>)
    objID, err := primitive.ObjectIDFromHex(id)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        c.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Invalid post ID"</span>})
        <span class="hljs-keyword">return</span>
    }

    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    <span class="hljs-keyword">var</span> post Post
    err = h.collection.FindOne(ctx, bson.M{<span class="hljs-string">"_id"</span>: objID}).Decode(&amp;post)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        c.JSON(http.StatusNotFound, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Post not found"</span>})
        <span class="hljs-keyword">return</span>
    }

    c.HTML(http.StatusOK, <span class="hljs-string">"post.html"</span>, post)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">CreatePost</span><span class="hljs-params">(c *gin.Context)</span></span> {
    c.HTML(http.StatusOK, <span class="hljs-string">"create.html"</span>, <span class="hljs-literal">nil</span>)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">EditPost</span><span class="hljs-params">(c *gin.Context)</span></span> {
    id := c.Param(<span class="hljs-string">"id"</span>)
    objID, err := primitive.ObjectIDFromHex(id)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        c.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Invalid post ID"</span>})
        <span class="hljs-keyword">return</span>
    }

    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    <span class="hljs-keyword">var</span> post Post
    err = h.collection.FindOne(ctx, bson.M{<span class="hljs-string">"_id"</span>: objID}).Decode(&amp;post)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        c.JSON(http.StatusNotFound, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Post not found"</span>})
        <span class="hljs-keyword">return</span>
    }

    c.HTML(http.StatusOK, <span class="hljs-string">"edit.html"</span>, post)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">SavePost</span><span class="hljs-params">(c *gin.Context)</span></span> {
    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    id := c.PostForm(<span class="hljs-string">"id"</span>)
    title := c.PostForm(<span class="hljs-string">"title"</span>)
    content := c.PostForm(<span class="hljs-string">"content"</span>)

    now := time.Now()

    <span class="hljs-keyword">if</span> id == <span class="hljs-string">""</span> {
        post := Post{
            Title:     title,
            Content:   content,
            CreatedAt: now,
            UpdatedAt: now,
        }

        result, err := h.collection.InsertOne(ctx, post)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
            <span class="hljs-keyword">return</span>
        }

        log.Printf(<span class="hljs-string">"Created post with ID: %v\n"</span>, result.InsertedID)
    } <span class="hljs-keyword">else</span> {
        objID, err := primitive.ObjectIDFromHex(id)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            c.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Invalid post ID"</span>})
            <span class="hljs-keyword">return</span>
        }

        update := bson.M{
            <span class="hljs-string">"$set"</span>: bson.M{
                <span class="hljs-string">"title"</span>:      title,
                <span class="hljs-string">"content"</span>:    content,
                <span class="hljs-string">"updated_at"</span>: now,
            },
        }

        result, err := h.collection.UpdateOne(ctx, bson.M{<span class="hljs-string">"_id"</span>: objID}, update)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
            <span class="hljs-keyword">return</span>
        }

        log.Printf(<span class="hljs-string">"Updated post with ID: %s (Modified %d documents)\n"</span>, id, result.ModifiedCount)
    }

    c.Redirect(http.StatusSeeOther, <span class="hljs-string">"/"</span>)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(h *Handler)</span> <span class="hljs-title">DeletePost</span><span class="hljs-params">(c *gin.Context)</span></span> {
    id := c.Param(<span class="hljs-string">"id"</span>)
    objID, err := primitive.ObjectIDFromHex(id)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        c.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"error"</span>: <span class="hljs-string">"Invalid post ID"</span>})
        <span class="hljs-keyword">return</span>
    }

    ctx, cancel := context.WithTimeout(context.Background(), <span class="hljs-number">5</span>*time.Second)
    <span class="hljs-keyword">defer</span> cancel()

    result, err := h.collection.DeleteOne(ctx, bson.M{<span class="hljs-string">"_id"</span>: objID})
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        c.JSON(http.StatusInternalServerError, gin.H{<span class="hljs-string">"error"</span>: err.Error()})
        <span class="hljs-keyword">return</span>
    }

    log.Printf(<span class="hljs-string">"Deleted %d document(s) with ID: %s\n"</span>, result.DeletedCount, id)
    c.Redirect(http.StatusSeeOther, <span class="hljs-string">"/"</span>)
}
</code></pre>
<p>The code above contains all the logic for managing blog posts. Here's what each component does:</p>
<ul>
<li><p><strong>Post struct:</strong> Defines the structure of a blog post document with fields for ID, title, content, and timestamps. The <code>bson</code> tags specify how fields are stored in MongoDB, while <code>json</code> tags handle JSON serialization.</p>
</li>
<li><p><strong>Handler struct:</strong> Contains a reference to the MongoDB database and the posts collection, providing a centralized way to access the database throughout your handlers.</p>
</li>
<li><p><strong>NewHandler function</strong>: Creates and initializes a new handler instance with the database connection and sets up the posts collection reference.</p>
</li>
<li><p><strong>HomePage:</strong> Retrieves all blog posts from the database using <code>Find()</code> with an empty filter and renders them using the <code>index.html</code> template.</p>
</li>
<li><p><strong>ViewPost:</strong> Fetches a single post by its ObjectID using <code>FindOne()</code> and displays it with the <code>post.html</code> template.</p>
</li>
<li><p><strong>CreatePost &amp; EditPost:</strong> Render the respective forms for creating new posts or editing existing ones.</p>
</li>
<li><p><strong>SavePost:</strong> Handles both creating new posts and updating existing ones. It checks if an ID is provided. If not, it creates a new post using <code>InsertOne()</code>. Otherwise, it updates the existing post using <code>UpdateOne()</code> with MongoDB's <code>$set</code> operator.</p>
</li>
<li><p><strong>DeletePost:</strong> Removes a post from the database using <code>DeleteOne()</code> and redirects back to the homepage.</p>
</li>
</ul>
<h3 id="heading-run-the-application">Run the application</h3>
<p>With everything set up, you can now launch your blog. Open your terminal and run:</p>
<pre><code class="lang-bash">go mod tidy &amp;&amp; go run main.go
</code></pre>
<p>Then, visit <a target="_blank" href="http://localhost:8080">http://localhost:8080</a> in your browser to see your blog in action.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753561817087/0e48d3d1-a6c0-4c5d-9245-cd6e86cd8596.png" alt="Blog management interface with a header &quot;Go Blog with MongoDB&quot; and a &quot;Create New Post&quot; button. Two blog post entries are shown with options to edit or delete." class="image--center mx-auto" width="512" height="283" loading="lazy"></p>
<h2 id="heading-thats-how-to-use-mongodb-with-go">That's How to Use MongoDB with Go</h2>
<p>In this tutorial, you built a simple blog application using Go and MongoDB. You learned how to connect to a MongoDB database using the official Go driver, perform CRUD operations, and render your results with the Gin web framework.</p>
<p>MongoDB’s flexible, document-based structure makes it a great fit for applications where data models need to evolve over time. It allows you to iterate quickly and adapt as your app grows.</p>
<p>As you expand this project, consider adding features such as user authentication, tagging or categorization, comments, pagination, or search functionality to enhance the user experience.</p>
<p>Cheers to building more with Go and MongoDB!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Code a full stack Instagram Clone with Laravel and MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ Are you ready to transform your web development skills by building a complex, real-world application? We just posted a course on the freeCodeCamp.org YouTube channel that will teach you how to use Laravel and MongoDB to create a full stack Instagram ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/code-a-full-stack-instagram-clone-with-laravel-and-mongodb/</link>
                <guid isPermaLink="false">67ed4efef1d155fc22688c46</guid>
                
                    <category>
                        <![CDATA[ Laravel ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 02 Apr 2025 14:51:42 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743605110164/9ae2ed21-4956-4b0e-b7c4-4ccc14e9df9f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Are you ready to transform your web development skills by building a complex, real-world application? We just posted a course on the freeCodeCamp.org YouTube channel that will teach you how to use Laravel and MongoDB to create a full stack Instagram clone.</p>
<p>I created this course myself. I’ll teach you how to code a feature-rich Instagram clone from the ground up, leveraging the power of the Laravel framework and the flexibility of the MongoDB database.</p>
<h3 id="heading-why-build-an-instagram-clone">Why Build an Instagram Clone?</h3>
<p>Building a clone of a popular application like Instagram forces you to tackle real-world challenges: managing user accounts, handling media uploads, implementing social interactions like likes and comments, and structuring data efficiently. Completing such a project demonstrates a strong grasp of full-stack development principles and provides tangible proof of your abilities to potential employers or clients.</p>
<h3 id="heading-the-tech-stack">The Tech Stack</h3>
<p>This tutorial pairs Laravel, a leading PHP framework, with MongoDB, a popular NoSQL database. This combination forms a very versatile technology stack for modern web development. It offers exceptional flexibility, scalability, and developer experience.</p>
<ul>
<li><p><strong>Laravel:</strong> Laravel provides a robust structure for building web applications. It follows the Model-View-Controller (MVC) architectural pattern, promoting clean, organized, and maintainable code. Laravel significantly simplifies common web development tasks such as routing (directing web requests), authentication (handling user login and registration), and interacting with databases through its powerful Object-Relational Mapper (ORM), Eloquent.</p>
</li>
<li><p><strong>MongoDB:</strong> Unlike traditional SQL databases that use tables and predefined schemas, MongoDB is a document database. It stores data in flexible, JSON-like documents, making it incredibly adaptable. This is ideal for applications where data structures might evolve over time. MongoDB's schema-less nature allows you to easily add new fields (like adding a 'username' or 'bio' to a user profile after initial creation, as demonstrated in the tutorial) without complex database migrations.</p>
</li>
</ul>
<p>Combining Laravel's structured development approach with MongoDB's flexible data storage provides the best of both worlds, especially for applications like an Instagram clone that manage diverse content types (profiles, posts, images, comments, likes) and their intricate relationships.</p>
<h3 id="heading-key-concepts-and-features">Key Concepts and Features</h3>
<p>Throughout the tutorial, you will gain hands-on experience with:</p>
<ol>
<li><p><strong>Full-Stack Integration:</strong> Learn how the frontend (what the user sees and interacts with) and the backend (server-side logic and database) work together seamlessly.</p>
</li>
<li><p><strong>Laravel Fundamentals:</strong> Master core Laravel concepts including the MVC pattern, defining routes (<code>web.php</code>), creating controllers to handle logic, building Eloquent models to interact with the database, and crafting user interfaces with the Blade templating engine.</p>
</li>
<li><p><strong>MongoDB with Laravel:</strong> Discover how to configure Laravel to work with MongoDB, install necessary drivers and packages (like <code>mongodb/laravel-mongodb</code>), and utilize Eloquent models specifically adapted for MongoDB collections and documents. You'll learn how relationships (like a user having many posts, or a post having many comments) are handled in a NoSQL context within Laravel.</p>
</li>
<li><p><strong>User Authentication &amp; Profiles:</strong> Implement secure user registration and login functionality using Laravel's built-in features. Build user profiles, allowing users to update their information (name, username, bio) and upload profile pictures.</p>
</li>
<li><p><strong>Core Social Features:</strong> Develop the essential functionalities of a social platform: creating posts with images and captions, displaying a feed of posts, implementing a like/unlike system, and adding/deleting comments on posts.</p>
</li>
<li><p><strong>Image Handling:</strong> Learn how to manage file uploads, specifically storing user-uploaded images (for posts and profiles) using Laravel's file storage system, initially locally and understanding how to potentially extend this to cloud storage like AWS S3.</p>
</li>
<li><p><strong>Database Management with MongoDB Atlas:</strong> Go beyond local development by learning how to set up a free cloud database cluster on MongoDB Atlas, configure security (users and network access), and connect your Laravel application to this cloud database – a crucial skill for deploying real-world applications.</p>
</li>
<li><p><strong>Frontend Styling:</strong> Utilize Bootstrap 5 (via CDN) to style the application, creating a clean and responsive user interface that mimics the look and feel of Instagram.</p>
</li>
</ol>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>To get the most out of this tutorial, you should have a foundational understanding of:</p>
<ul>
<li><p>PHP basics</p>
</li>
<li><p>Web fundamentals (HTML, CSS, basic JavaScript, HTTP concepts)</p>
</li>
<li><p>Command-line usage</p>
</li>
<li><p>You'll also need PHP, Composer (PHP package manager), and MongoDB installed on your local machine. The tutorial briefly covers installation pointers for different operating systems.</p>
</li>
</ul>
<p>Ready to build your own Instagram clone and significantly boost your web development expertise? Watch the full course on <a target="_blank" href="https://youtu.be/VK-2j5CNsvM">the freeCodeCamp.org YouTube channel</a> (1-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/VK-2j5CNsvM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a MERN Stack To-Do App ]]>
                </title>
                <description>
                    <![CDATA[ This guide will walk you through building a full-stack MERN To-Do application. It covers setting up the environment, writing code to demonstrate core CRUD (Create, Read, Update, Delete) operations, and connecting the application to MongoDB Atlas, a f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-mern-stack-to-do-app/</link>
                <guid isPermaLink="false">67c74d6473daa61c95803cfc</guid>
                
                    <category>
                        <![CDATA[ MERN Stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ todoapp ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Casmir Onyekani ]]>
                </dc:creator>
                <pubDate>Tue, 04 Mar 2025 18:58:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741102112733/3aa43545-c095-4a47-8787-130b470f6ce1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This guide will walk you through building a full-stack MERN To-Do application. It covers setting up the environment, writing code to demonstrate core CRUD (Create, Read, Update, Delete) operations, and connecting the application to MongoDB Atlas, a free cloud database.</p>
<p>Before diving into this article, I recommend that you have a foundational understanding of HTML, CSS, and JavaScript, as well as some knowledge of frontend and backend frameworks and libraries.</p>
<p>My primary focus will be on functionality, allowing you to customize the design as you see fit. The commands I’ll use here are tailored for Windows, so if you're using Linux, macOS, or Ubuntu, you may need to adjust them accordingly.</p>
<p>By the end of this guide, you'll have a fully functional To-Do app up and running on your system.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-introduction-to-the-mern-stack">Introduction to the MERN Stack</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-development-environment">How to Set Up Your Development environment</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-install-nodejs-and-npm-node-package-manager">Install Node.js and npm - Node Package Manager</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-a-new-mern-project">How to Set Up a New MERN Project</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-frontend-setup">Frontend Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-build-the-to-do-app-ui">Build the To-Do App UI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-displaying-your-tasks-in-the-ui">Displaying your tasks in the UI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-give-your-app-customized-styling">Give Your App Customized Styling</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-backend-setup">Backend Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-set-up-mongodb-atlas">Set Up MongoDB Atlas</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-run-the-application">Run the Application</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-introduction-to-the-mern-stack">Introduction to the MERN Stack</h2>
<p>The MERN stack is a popular JavaScript stack for building modern web applications. It consists of:</p>
<ul>
<li><p><strong>MongoDB</strong>: A NoSQL database for storing data.</p>
</li>
<li><p><strong>Express.js</strong>: A backend framework for building APIs.</p>
</li>
<li><p><strong>React (UI library) + Vite (build tool) + TypeScript (typed JavaScript)</strong>: A modern frontend stack for building scalable and maintainable user interfaces.</p>
</li>
<li><p><strong>Node.js</strong>: A runtime environment for executing JavaScript on the server.</p>
</li>
</ul>
<h2 id="heading-how-to-set-up-your-development-environment">How to Set Up Your Development environment</h2>
<h3 id="heading-install-nodejs-and-npm-node-package-manager">Install Node.js and npm (Node Package Manager)</h3>
<p>Instead of installing Node.js and npm in your project folder, I advise you to install them in your system's root directory so that you can use them in any project, not just this one.</p>
<p>First, download and install Node.js (which includes npm) from the <a target="_blank" href="https://nodejs.org/en">official website</a> if you don’t have it already.</p>
<p>After installation, open your command line (I am using Git Bash) and verify the installation by running the following commands:</p>
<pre><code class="lang-bash">node -v
npm -v
</code></pre>
<p>You should see the installed versions of Node.js and npm if correctly installed.</p>
<h2 id="heading-how-to-set-up-a-new-mern-project">How to Set Up a New MERN Project</h2>
<p>Create a project folder and open your code editor by running these commands:</p>
<pre><code class="lang-bash">mkdir mern-todo-app
<span class="hljs-built_in">cd</span> mern-todo-app
code .
</code></pre>
<p>The command <code>code .</code> automatically opens VS Code. If it doesn’t, open VS Code manually and navigate to your <code>mern-todo-app</code> folder.</p>
<h3 id="heading-frontend-setup">Frontend Setup</h3>
<h4 id="heading-set-up-vite-with-react-and-typescript">Set Up Vite with React and TypeScript</h4>
<p>Make sure you are in your project root directory (<code>mern-todo-app</code>), then run the following command:</p>
<pre><code class="lang-bash">npm create vite@latest frontend --template react-ts
</code></pre>
<p>This command will create a TypeScript-based React frontend inside the <code>frontend</code> folder within your <code>mern-todo-app</code> directory.</p>
<h4 id="heading-install-axios-for-making-api-requests">Install Axios for Making API Requests</h4>
<p>Axios is a popular JavaScript library used to make HTTP requests from the frontend to a backend API. It simplifies sending GET, POST, PUT, and DELETE requests and handling responses.</p>
<p>To install Axios, run the following command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> frontend
npm install axios
</code></pre>
<h3 id="heading-build-the-to-do-app-ui">Build the To-Do App UI</h3>
<p>Inside the <code>src</code> folder, create an <code>App.tsx</code> file if it doesn’t already exist, and add the below code. It’s a lot, but don’t worry – I’ll break it down bit by bit afterwards:</p>
<p><code>frontend/src/App.tsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BLOCK 1: Importing Dependencies</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> TodoList <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/TodoList.tsx"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-comment">// BLOCK 2: Defining Task Interface</span>
interface Task {
  <span class="hljs-attr">_id</span>: string;
  title: string;
  completed: boolean;
}

<span class="hljs-comment">// BLOCK 3: Setting Up State Variables</span>
<span class="hljs-keyword">const</span> App: React.FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// State for tasks, new task text, and editing controls</span>
  <span class="hljs-keyword">const</span> [tasks, setTasks] = useState&lt;Task[]&gt;([]);
  <span class="hljs-keyword">const</span> [task, setTask] = useState&lt;string&gt;(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [editingTaskId, setEditingTaskId] = useState&lt;string | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [editingTitle, setEditingTitle] = useState&lt;string&gt;(<span class="hljs-string">""</span>);

  <span class="hljs-comment">// BLOCK 4: Fetch tasks from the backend on component mount</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchTasks = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get&lt;Task[]&gt;(<span class="hljs-string">`http://localhost:5000/api/tasks`</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Fetched tasks:"</span>, response.data); <span class="hljs-comment">// Debugging log</span>
        setTasks(response.data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching tasks:"</span>, error);
      }
    };
    fetchTasks();
  }, []);

  <span class="hljs-comment">// BLOCK 5: Adding a Task</span>
  <span class="hljs-keyword">const</span> addTask = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">if</span> (!task) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">try</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Adding task:"</span>, task); <span class="hljs-comment">// Debugging log</span>
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post&lt;Task&gt;(
        <span class="hljs-string">`http://localhost:5000/api/tasks`</span>,
        { <span class="hljs-attr">title</span>: task },
        { <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> } }
      );
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Task added response:"</span>, response.data);
      setTasks([...tasks, response.data]);
      setTask(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error adding task:"</span>, error);
    }
  };

  <span class="hljs-comment">// BLOCK 6: Delete a task</span>
  <span class="hljs-keyword">const</span> deleteTask = <span class="hljs-keyword">async</span> (id: string) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> axios.delete(<span class="hljs-string">`http://localhost:5000/api/tasks/<span class="hljs-subst">${id}</span>`</span>);
      setTasks(tasks.filter(<span class="hljs-function">(<span class="hljs-params">t</span>) =&gt;</span> t._id !== id));
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error deleting task:"</span>, error);
    }
  };

  <span class="hljs-comment">// BLOCK 7: Updating a Task</span>
  <span class="hljs-keyword">const</span> updateTask = <span class="hljs-keyword">async</span> (id: string, <span class="hljs-attr">updatedTask</span>: Partial&lt;Task&gt;) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.put(
        <span class="hljs-string">`http://localhost:5000/api/tasks/<span class="hljs-subst">${id}</span>`</span>,
        updatedTask,
        { <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> } }
      );

      setTasks(
        tasks.map(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span>
          task._id === id ? { ...task, ...response.data } : task
        )
      );
      setEditingTaskId(<span class="hljs-literal">null</span>);
      setEditingTitle(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error updating task:"</span>, error);
    }
  };

  <span class="hljs-comment">// BLOCK 8: Handling Edits</span>
  <span class="hljs-keyword">const</span> startEditing = <span class="hljs-function">(<span class="hljs-params">id: string</span>) =&gt;</span> {
    setEditingTaskId(id);
  };

  <span class="hljs-comment">// Handle title change during editing</span>
  <span class="hljs-keyword">const</span> handleEditChange = <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLInputElement&gt;</span>) =&gt;</span> {
    setEditingTitle(e.target.value);
  };

  <span class="hljs-comment">// BLOCK 9: Render the app</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Todo App<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{task}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTask(e.target.value)}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addTask}</span>&gt;</span>Add Task<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TodoList</span>
        <span class="hljs-attr">tasks</span>=<span class="hljs-string">{tasks}</span>
        <span class="hljs-attr">deleteTask</span>=<span class="hljs-string">{deleteTask}</span>
        <span class="hljs-attr">updateTask</span>=<span class="hljs-string">{updateTask}</span>
        <span class="hljs-attr">editingTitle</span>=<span class="hljs-string">{editingTitle}</span>
        <span class="hljs-attr">setEditingTitle</span>=<span class="hljs-string">{setEditingTitle}</span>
        <span class="hljs-attr">editingTaskId</span>=<span class="hljs-string">{editingTaskId}</span>
        <span class="hljs-attr">setEditingTaskId</span>=<span class="hljs-string">{setEditingTaskId}</span>
        <span class="hljs-attr">startEditing</span>=<span class="hljs-string">{startEditing}</span>
        <span class="hljs-attr">handleEditChange</span>=<span class="hljs-string">{handleEditChange}</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-comment">// BLOCK 10: Exporting the Component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1:</strong> Importing dependencies</p>
<ul>
<li><p><code>React, { useState, useEffect }</code>: Manages component state and side effects.</p>
</li>
<li><p><code>axios</code>: Handles API requests.</p>
</li>
<li><p><code>TodoList.tsx</code>: A child component to display and manage tasks.</p>
</li>
<li><p><code>App.css</code>: Styles the app.</p>
</li>
</ul>
<p><strong>BLOCK 2:</strong> Defining the task interface</p>
<ul>
<li>Defines the structure of a task (<code>_id</code>, <code>title</code>, <code>completed</code>).</li>
</ul>
<p><strong>BLOCK 3:</strong> Setting up state variables</p>
<ul>
<li><p><code>tasks</code>: Stores the list of tasks.</p>
</li>
<li><p><code>task</code>: Holds input for new tasks.</p>
</li>
<li><p><code>editingTaskId</code>: Tracks the task being edited.</p>
</li>
<li><p><code>editingTitle</code>: Stores the updated title while editing.</p>
</li>
</ul>
<p><strong>BLOCK 4:</strong> Fetching tasks from the backend (<code>useEffect</code>)</p>
<ul>
<li><p>Runs once when the app loads.</p>
</li>
<li><p>Calls the API (<code>GET /api/tasks</code>) to get tasks and updates <code>tasks</code>.</p>
</li>
<li><p>Error handling**:** Logs an error message if the fetching request fails</p>
</li>
</ul>
<p><strong>BLOCK 5:</strong> Adding a task</p>
<ul>
<li><p>Sends a <code>POST</code> request to add a new task.</p>
</li>
<li><p>Updates <code>tasks</code> with the new task.</p>
</li>
<li><p>Error handling**:** Logs an error message if the adding task request fails</p>
</li>
</ul>
<p><strong>BLOCK 6:</strong> Deleting a task</p>
<ul>
<li><p>Sends a <code>DELETE</code> request to remove a task.</p>
</li>
<li><p>Updates <code>tasks</code> by filtering out the deleted task.</p>
</li>
<li><p>Error handling**:** Logs an error message if the deleting task request fails</p>
</li>
</ul>
<p><strong>BLOCK 7:</strong> Updating a task</p>
<ul>
<li><p>Sends a <code>PUT</code> request to update a task’s title.</p>
</li>
<li><p>Updates <code>tasks</code> with the new title.</p>
</li>
<li><p>Error handling**:** Logs an error message if the update request fails</p>
</li>
</ul>
<p><strong>BLOCK 8:</strong> Handling edits</p>
<ul>
<li><p><code>startEditing(id)</code>: Sets a task into edit mode.</p>
</li>
<li><p><code>handleEditChange(e)</code>: Updates the editing input.</p>
</li>
</ul>
<p><strong>BLOCK 9:</strong> Rendering the UI</p>
<ul>
<li><p>Displays an input field and button to add tasks.</p>
</li>
<li><p>Passes task data and functions (<code>deleteTask</code>, <code>updateTask</code>, etc.) to <code>TodoList.tsx</code>.</p>
</li>
</ul>
<p><strong>BLOCK 10:</strong> Exporting the component</p>
<ul>
<li><code>export default App;</code>: Makes <code>App</code> usable in other files.</li>
</ul>
<h3 id="heading-displaying-your-tasks-in-the-ui">Displaying your tasks in the UI</h3>
<p>Inside the <code>src</code> folder, create a new folder named <code>components</code>. Then add a <code>TodoList.tsx</code> file inside it with the below code.</p>
<p><code>src/components/TodoList.tsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BLOCK 1: Importing Dependencies</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// BLOCK 2: Defining Interfaces</span>
interface Task {
  <span class="hljs-attr">_id</span>: string; <span class="hljs-comment">// Unique ID for the task</span>
  title: string; <span class="hljs-comment">// Task name</span>
  completed: boolean; <span class="hljs-comment">// True if done, False if not</span>
}

interface TodoListProps {
  <span class="hljs-attr">tasks</span>: Task[];
  deleteTask: <span class="hljs-function">(<span class="hljs-params">id: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  updateTask: <span class="hljs-function">(<span class="hljs-params">id: string, updatedTask: Partial&lt;Task&gt;</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  editingTitle: string;
  setEditingTitle: <span class="hljs-function">(<span class="hljs-params">title: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  editingTaskId: string | <span class="hljs-literal">null</span>;
  setEditingTaskId: <span class="hljs-function">(<span class="hljs-params">id: string | <span class="hljs-literal">null</span></span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  startEditing: <span class="hljs-function">(<span class="hljs-params">id: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  handleEditChange: <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLInputElement&gt;</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
}

<span class="hljs-comment">// BLOCK 3: Declares the TodoList Component</span>
<span class="hljs-keyword">const</span> TodoList: React.FC&lt;TodoListProps&gt; = <span class="hljs-function">(<span class="hljs-params">{
  tasks,
  deleteTask,
  updateTask,
  editingTitle,
  setEditingTitle,
  editingTaskId,
  setEditingTaskId,
  startEditing,
  handleEditChange,
}</span>) =&gt;</span> {

  <span class="hljs-comment">// BLOCK 4: Rendering the Task List and handling task actions</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {tasks.map((task) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{task._id}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
            <span class="hljs-attr">checked</span>=<span class="hljs-string">{task.completed}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{()</span> =&gt;</span> updateTask(task._id, { completed: !task.completed })}
          /&gt;
          {editingTaskId === task._id ? (
            <span class="hljs-tag">&lt;&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{editingTitle}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleEditChange}</span> /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
                  updateTask(task._id, { title: editingTitle });
                  setEditingTaskId(null);
                }}
              &gt;
                Save
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/&gt;</span>
          ) : (
            <span class="hljs-tag">&lt;&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">textDecoration:</span> <span class="hljs-attr">task.completed</span> ? "<span class="hljs-attr">line-through</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">none</span>" }}&gt;</span>
                {task.title}
              <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deleteTask(task._id)}&gt;Delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
                    startEditing(task._id);
                    setEditingTitle(task.title);
                  }}
                &gt;
                  Edit
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/&gt;</span></span>
          )}
        &lt;/li&gt;
      ))}
    &lt;/ul&gt;
  );
};

<span class="hljs-comment">// BLOCK 5: Exporting the Component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TodoList;
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1:</strong> Importing dependencies</p>
<ul>
<li>React: Enables functional component creation.</li>
</ul>
<p><strong>BLOCK 2:</strong> Defining interfaces</p>
<ul>
<li><p>Task interface: Defines <code>_id</code>, <code>title</code>, and <code>completed</code> properties.</p>
</li>
<li><p>TodoListProps interface: Defines props passed to the <code>TodoList</code> component</p>
</li>
</ul>
<p><strong>BLOCK 3</strong>: Declares the <code>TodoList</code> component</p>
<ul>
<li><p>Defines a functional React component (<code>TodoList</code>) using TypeScript (<code>React.FC&lt;TodoListProps&gt;</code>).</p>
</li>
<li><p>Extracts the listed props from <code>TodoListProps</code> and prepares the component for rendering.</p>
</li>
</ul>
<p><strong>BLOCK 4</strong>: Rendering the Task List and handling task actions</p>
<ul>
<li><p>Maps through <code>tasks</code> to display each task inside a <code>&lt;ul&gt;</code>.</p>
</li>
<li><p>Checkbox toggles <code>completed</code> status using <code>updateTask()</code>.</p>
</li>
<li><p>Conditional rendering:</p>
<ul>
<li><p>If a task is being edited, an input field appears for editing.</p>
</li>
<li><p>Otherwise, the task title is displayed with a strikethrough if completed</p>
</li>
</ul>
</li>
<li><p>Save button: Updates the task title using <code>updateTask()</code>, then exits edit mode.</p>
</li>
<li><p>Delete button: Calls <code>deleteTask()</code> to remove a task.</p>
</li>
<li><p>Edit button: Enables edit mode, setting <code>editingTaskId</code> and <code>editingTitle</code>.</p>
</li>
</ul>
<p><strong>BLOCK 5</strong>: Exporting the component</p>
<ul>
<li>Makes <code>TodoList</code> available for use in other components.</li>
</ul>
<h3 id="heading-give-your-app-customized-styling">Give Your App Customized Styling</h3>
<p>Inside your <code>src</code> folder, create <code>App.css</code> if it doesn’t exist and replace the content with your desired styling. Let’s give the frontend a finishing touch.</p>
<p><code>src/App.css</code>:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Center the app in the middle of the screen */</span>
<span class="hljs-selector-tag">html</span>, <span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-family</span>: Arial, sans-serif;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f4f4f4</span>; <span class="hljs-comment">/* Light gray background */</span>
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">overflow-x</span>: hidden; <span class="hljs-comment">/* Prevent horizontal scrolling */</span>
}

<span class="hljs-comment">/* Style the main app container */</span>
<span class="hljs-selector-class">.App</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">background</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">10px</span>; <span class="hljs-comment">/* Rounded corners */</span>
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">10px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>); <span class="hljs-comment">/* Light shadow effect */</span>
  <span class="hljs-attribute">width</span>: <span class="hljs-number">90%</span>; <span class="hljs-comment">/* Make it flexible */</span>
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">350px</span>; <span class="hljs-comment">/* Prevent exceeding max size */</span>
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-comment">/* Add spacing below the title */</span>
<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-comment">/* Style input fields */</span>
<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-comment">/* Full width */</span>
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-comment">/* Style buttons */</span>
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-comment">/* Make buttons full width */</span>
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#007bff</span>; <span class="hljs-comment">/* Blue background */</span>
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">14px</span>;
  <span class="hljs-attribute">transition</span>: background-color <span class="hljs-number">0.3s</span> ease-in-out;
}

<span class="hljs-comment">/* Change button color when hovered */</span>
<span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0056b3</span>;
}

<span class="hljs-comment">/* Remove default list styles */</span>
<span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-comment">/* Style list items */</span>
<span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">5px</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">2px</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>); <span class="hljs-comment">/* Add a subtle shadow */</span>
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-comment">/* Allow task text to take available space */</span>
<span class="hljs-selector-tag">span</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-comment">/* Style completed tasks */</span>
<span class="hljs-selector-tag">span</span><span class="hljs-selector-class">.completed</span> {
  <span class="hljs-attribute">text-decoration</span>: line-through;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#888</span>;
}

<span class="hljs-comment">/* Adjust the width of input fields inside the list */</span>
<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"text"</span>]</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
}

<span class="hljs-comment">/* Style the checkbox */</span>
<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"checkbox"</span>]</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">18px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">18px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">accent-color</span>: <span class="hljs-number">#007bff</span>; <span class="hljs-comment">/* Blue checkbox to match buttons */</span>
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-comment">/* Styling for editing mode */</span>
<span class="hljs-selector-class">.editing-container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-comment">/* Responsive styling for smaller screens */</span>
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">400px</span>) {
  <span class="hljs-selector-class">.App</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">95%</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">max-width</span>: none; <span class="hljs-comment">/* Remove fixed width restriction */</span>
  }

  <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">flex-direction</span>: column;
    <span class="hljs-attribute">align-items</span>: flex-start;
  }

  <span class="hljs-selector-tag">input</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  }

  <span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  }
}
</code></pre>
<p>Here’s what this CSS code does:</p>
<p>First, it centers the app (<code>html, body</code>):</p>
<ul>
<li><p>Uses <code>flexbox</code> to center the app vertically and horizontally.</p>
</li>
<li><p>Sets <code>height: 100vh</code> for full-screen height.</p>
</li>
<li><p>Prevents horizontal scrolling with <code>overflow-x: hidden</code>.</p>
</li>
</ul>
<p>Then it styles the main app container (<code>.App</code>):</p>
<ul>
<li><p>Adds a white background with rounded corners and a shadow.</p>
</li>
<li><p>Ensures responsiveness with <code>width: 90%</code> and <code>max-width: 350px</code>.</p>
</li>
</ul>
<p>Next, we handle typography and layout:</p>
<ul>
<li><p>Sets <code>Arial, sans-serif</code> as the font.</p>
</li>
<li><p>Adds spacing below the title (<code>h1</code>).</p>
</li>
<li><p>Ensures task text takes available space with <code>span { flex: 1; }</code>.</p>
</li>
</ul>
<p>Then we deal with input and button styling:</p>
<ul>
<li><p>Inputs are full-width, styled with padding, borders, and rounded corners.</p>
</li>
<li><p>Buttons are blue, full-width, with hover effects (<code>background-color: #0056b3</code>).</p>
</li>
</ul>
<p>And then task list styling <strong>(</strong><code>ul, li, span.completed</code>):</p>
<ul>
<li><p>Removes default list styles.</p>
</li>
<li><p>Each task (<code>li</code>) has a white background, padding, rounded corners, and a shadow.</p>
</li>
<li><p>Completed tasks are styled with a <code>line-through</code> and faded text color.</p>
</li>
</ul>
<p>Next, we handle checkbox and editing mode styling:</p>
<ul>
<li><p>Styled blue checkboxes (<code>accent-color: #007bff</code>).</p>
</li>
<li><p>Adds an <code>editing-container</code> with <code>display: flex;</code> for edit mode.</p>
</li>
</ul>
<p>And finally, we make the design responsive (<code>@media (max-width: 400px)</code>):</p>
<ul>
<li><p>Adjusts <code>.App</code> width and padding for small screens.</p>
</li>
<li><p>Stacks list items (<code>li</code>) vertically instead of side-by-side.</p>
</li>
</ul>
<h3 id="heading-backend-setup">Backend Setup</h3>
<p>In your VS Code terminal, make sure you are in your project root directory (inside <code>mern-todo-app</code>) and then create a folder called <code>backend</code>. Navigate to the <code>backend</code> folder and initialize <code>Node.js</code>:</p>
<pre><code class="lang-bash">mkdir backend
<span class="hljs-built_in">cd</span> backend
npm init -y
</code></pre>
<h4 id="heading-install-dependencies">Install Dependencies</h4>
<p>Still inside your <code>backend</code> folder, run this command:</p>
<pre><code class="lang-bash">npm install express mongoose dotenv cors
</code></pre>
<p>In this command,</p>
<ul>
<li><p><code>express</code> is a fast and minimal web framework for Node.js used to create server-side applications and APIs.</p>
</li>
<li><p><code>mongoose</code> is an Object Data Modeling (ODM) library for MongoDB, simplifying database interactions.</p>
</li>
<li><p><code>dotenv</code> loads environment variables from a <code>.env</code> file, keeping sensitive data secure.</p>
</li>
<li><p><code>cors</code> enables Cross-Origin Resource Sharing, allowing frontend applications to communicate with the backend across different domains.</p>
</li>
</ul>
<h4 id="heading-create-a-serverjs-file">Create a server.js File</h4>
<p>Inside your <code>backend</code> folder, create a file named <code>server.js</code> and enter the following code:</p>
<p><code>backend/server.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BLOCK 1: Importing Dependencies</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>);
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>);

<span class="hljs-comment">// BLOCK 2: Configuring the Express App</span>
dotenv.config();

<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// BLOCK 3: Setting Up Middleware</span>
app.use(cors());
app.use(express.json());

<span class="hljs-comment">// BLOCK 4: Connecting to MongoDB</span>
<span class="hljs-keyword">const</span> connectDB = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> mongoose.connect(process.env.MONGO_URI);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"MongoDB Connected"</span>);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"MongoDB Connection Failed:"</span>, err);
    process.exit(<span class="hljs-number">1</span>); <span class="hljs-comment">// Exit process with failure</span>
  }
};

<span class="hljs-comment">// Call the database connection function</span>
connectDB();

<span class="hljs-comment">// BLOCK 5: Defining Routes</span>
<span class="hljs-keyword">const</span> tasksRoutes = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./routes/tasks"</span>);
app.use(<span class="hljs-string">"/api/tasks"</span>, tasksRoutes);

<span class="hljs-comment">// BLOCK 6: Starting the Server</span>
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">5000</span>;
app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1</strong>: Importing dependencies</p>
<ul>
<li><p>express**:** Creates the server.</p>
</li>
<li><p>mongoose**:** Connects to MongoDB.</p>
</li>
<li><p>cors**:** Enables cross-origin requests.</p>
</li>
<li><p>dotenv**:** Loads environment variables.</p>
</li>
</ul>
<p><strong>BLOCK 2</strong>: Configuring the Express app</p>
<ul>
<li><p>Loads environment variables using <code>dotenv.config()</code>.</p>
</li>
<li><p>Initializes <code>express()</code> to create an app instance.</p>
</li>
</ul>
<p><strong>BLOCK 3</strong>: Setting up middleware</p>
<ul>
<li><p>cors()<strong>:</strong> Allows API access from different origins.</p>
</li>
<li><p>express.json()<strong>:</strong> Parses incoming JSON requests.</p>
</li>
</ul>
<p><strong>BLOCK 4</strong>: Connecting to MongoDB</p>
<ul>
<li><p>Defines <code>connectDB()</code> to connect to MongoDB using <code>MONGO_URI</code>.</p>
</li>
<li><p>Logs success or failure and exits on error.</p>
</li>
</ul>
<p><strong>BLOCK 5</strong>: Defining routes</p>
<ul>
<li><p>Imports <code>tasksRoutes</code> from <code>./routes/tasks</code>.</p>
</li>
<li><p>Uses <code>/api/tasks</code> as the base route for task operations.</p>
</li>
</ul>
<p><strong>BLOCK 6</strong>: Starting the server</p>
<ul>
<li><p>Sets <code>PORT</code> from <code>.env</code> or defaults to <code>5000</code>.</p>
</li>
<li><p>Starts the server and logs the running port.</p>
</li>
</ul>
<h4 id="heading-define-task-model">Define Task Model</h4>
<p>In your <code>backend</code> folder, create a <code>model</code> folder. Inside <code>model</code>, create a file named <code>Task.js</code> and add the following code:</p>
<p><code>backend/model/Task.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BLOCK 1: Importing Mongoose</span>
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);

<span class="hljs-comment">// BLOCK 2: Defining Task Schema</span>
<span class="hljs-keyword">const</span> TaskSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
    <span class="hljs-attr">title</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
    <span class="hljs-attr">completed</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span> },
});

<span class="hljs-comment">// BLOCK 3: Creating and Exporting the Model</span>
<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">"Task"</span>, TaskSchema);
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1</strong>: Importing Mongoose</p>
<ul>
<li><code>mongoose</code>: Used to define the schema and interact with MongoDB.</li>
</ul>
<p><strong>BLOCK 2</strong>: Defining the task schema</p>
<ul>
<li><p><code>title</code>: A required string field for the task title.</p>
</li>
<li><p><code>completed</code>: A boolean field indicating task status (default: <code>false</code>).</p>
</li>
</ul>
<p><strong>BLOCK 3</strong>: Creating and exporting the model</p>
<ul>
<li><p>Creates a Mongoose model named <code>"Task"</code> based on <code>TaskSchema</code>.</p>
</li>
<li><p>Exports the model for use in other parts of the application</p>
</li>
</ul>
<h4 id="heading-define-routes">Define Routes</h4>
<p>In your <code>backend</code> folder, create a <code>routes</code> folder. Inside <code>routes</code>, create a file named <code>tasks.js</code> and add the following code:</p>
<p><code>backend/routes/tasks.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BOCK 1: Import dependencies</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> Task = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../models/Task"</span>);

<span class="hljs-keyword">const</span> router = express.Router();

<span class="hljs-comment">// BLOCK 2: GET all tasks</span>
router.get(<span class="hljs-string">"/"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> tasks = <span class="hljs-keyword">await</span> Task.find();
    res.json(tasks);
  } <span class="hljs-keyword">catch</span> (err) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: err.message });
  }
});

<span class="hljs-comment">// BLOCK 3: POST a new task</span>
router.post(<span class="hljs-string">"/"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { title } = req.body;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Received title:"</span>, title); <span class="hljs-comment">// Debugging log</span>

  <span class="hljs-keyword">if</span> (!title) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Task title is required"</span> });
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> newTask = <span class="hljs-keyword">new</span> Task({ title });
    <span class="hljs-keyword">await</span> newTask.save();
    res.status(<span class="hljs-number">201</span>).json(newTask);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err.message);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: err.message });
  }
});

<span class="hljs-comment">// BLOCK 4: DELETE a task</span>
router.delete(<span class="hljs-string">"/:id"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { id } = req.params;
    <span class="hljs-keyword">await</span> Task.findByIdAndDelete(id);
    res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Task deleted"</span> });
  } <span class="hljs-keyword">catch</span> (err) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: err.message });
  }
});

<span class="hljs-comment">// BLOCK 5: UPDATE a task</span>
router.put(<span class="hljs-string">"/:id"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { id } = req.params;

    <span class="hljs-keyword">const</span> updatedTask = <span class="hljs-keyword">await</span> Task.findByIdAndUpdate(
      id,
      req.body,
      { <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span> } <span class="hljs-comment">// Return the updated task</span>
    );
    res.json(updatedTask);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Error updating task"</span> });
  }
});

<span class="hljs-comment">// BLOCK 6: Export the router</span>
<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1</strong>: Import dependencies</p>
<ul>
<li><p>express: Handles routing.</p>
</li>
<li><p>Task: Imports the Task model.</p>
</li>
<li><p>express.Router(): Creates a router for task-related routes.</p>
</li>
</ul>
<p><strong>BLOCK 2</strong>: GET all tasks</p>
<ul>
<li><p>Fetches all tasks from the database.</p>
</li>
<li><p>Sends the tasks as a JSON response.</p>
</li>
<li><p>Handles errors with a 500 status.</p>
</li>
</ul>
<p><strong>BLOCK 3</strong>: POST a new task</p>
<ul>
<li><p>Extracts <code>title</code> from the request body.</p>
</li>
<li><p>Logs the received title for debugging.</p>
</li>
<li><p>Validates the title (returns 400 if missing).</p>
</li>
<li><p>Saves the task to the database and returns it.</p>
</li>
</ul>
<p><strong>BLOCK 4</strong>: DELETE a task</p>
<ul>
<li><p>Extracts <code>id</code> from the request params.</p>
</li>
<li><p>Deletes the task from the database.</p>
</li>
<li><p>Returns a success message.</p>
</li>
</ul>
<p><strong>BLOCK 5</strong>: UPDATE a task</p>
<ul>
<li><p>Extracts <code>id</code> from the request params.</p>
</li>
<li><p>Updates the task using request body data.</p>
</li>
<li><p>Returns the updated task.</p>
</li>
</ul>
<p><strong>BLOCK 6</strong>: Export the router</p>
<ul>
<li>Exports <code>router</code> for use in other parts of the app.</li>
</ul>
<p>This Express.js router handles CRUD operations for a <code>Task</code> model using MongoDB. It defines routes to get all tasks, add a new task, delete a task by ID, and update a task's title by ID. Error handling ensures proper responses for missing data or server issues.</p>
<h4 id="heading-create-a-env-file">Create a .env file</h4>
<p>In your backend folder, create a <code>.env</code> file and add the following:</p>
<p><code>backend/.env</code>:</p>
<pre><code class="lang-javascript">MONGO_URI=your_mongodb_atlas_uri
</code></pre>
<h3 id="heading-set-up-mongodb-atlas">Set Up MongoDB Atlas</h3>
<p>MongoDB Atlas is a cloud-based MongoDB service. We'll use the free tier for this project.</p>
<p>To get started, go to <a target="_blank" href="https://www.mongodb.com/products/platform/atlas-database">MongoDB Atlas</a> and create an account or log in.</p>
<p>Follow the steps to create a free cluster. Once the cluster is created, click Connect and follow the instructions to:</p>
<ul>
<li><p>Whitelist your IP address to allow MongoDB access using your environment variable.</p>
</li>
<li><p>Create a database user.</p>
</li>
<li><p>Get the connection string.</p>
</li>
</ul>
<p>Replace the <code>your_mongodb_atlas_uri</code> in <code>.env</code> file with your MongoDB Atlas connection string.</p>
<p>If you are still not comfortable with how to set up MongoDB atlas, read this: <a target="_blank" href="https://www.freecodecamp.org/news/get-started-with-mongodb-atlas/">MongoDB Atlas Tutorial – How to Get Started</a>.</p>
<h3 id="heading-run-the-application">Run the Application</h3>
<p>To run the application successfully using <code>npm run dev</code>, you need to install a dependency that will start both the frontend and backend simultaneously. You can do this using <a target="_blank" href="https://www.npmjs.com/package/concurrently">concurrently</a><strong>.</strong></p>
<p>Install concurrently:</p>
<p>Open your terminal, navigate to your project root directory (<code>mern-todo-app</code>), and run:</p>
<pre><code class="lang-bash">npm install concurrently
</code></pre>
<h4 id="heading-configure-packagejson">Configure <code>package.json</code>:</h4>
<p>After installing concurrently, ensure that you have a <code>package.json</code> file in your project root directory. If it doesn't exist, create one and add the following code:</p>
<p><code>mern-todo-app/package.json</code>:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"mern-todo-app"</span>,
    <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
    <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"scripts"</span>: {
        <span class="hljs-attr">"start"</span>: <span class="hljs-string">"cd backend &amp;&amp; npm start"</span>,
        <span class="hljs-attr">"client"</span>: <span class="hljs-string">"cd frontend &amp;&amp; npm run dev"</span>,
        <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"concurrently \"npm run start\" \"npm run client\""</span>
    },
    <span class="hljs-attr">"dependencies"</span>: {
        <span class="hljs-attr">"concurrently"</span>: <span class="hljs-string">"^8.2.2"</span>
    }
}
</code></pre>
<p>This <code>package.json</code> file configures the application by defining:</p>
<ul>
<li><p>Project metadata (<code>name, version, private flag</code>).</p>
</li>
<li><p>Scripts (<code>start</code>, <code>client</code>, and <code>dev</code>) to start the backend, run the frontend, and execute both simultaneously.</p>
</li>
<li><p>Dependencies, including <code>concurrently</code>, which enables running multiple scripts in parallel.</p>
</li>
<li><p>The project is set to private to prevent accidental publishing.</p>
</li>
</ul>
<h4 id="heading-start-the-application">Start the Application</h4>
<p>Ensure everything is set up and saved, then run the following command from the project root:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>If the application starts successfully, you should see messages like:</p>
<pre><code class="lang-nginx"><span class="hljs-attribute">Server</span> running <span class="hljs-literal">on</span> port <span class="hljs-number">5000</span>
MongoDB Connected
</code></pre>
<h4 id="heading-view-the-application">View the Application</h4>
<p>Open your browser and navigate to:</p>
<ul>
<li><p>Frontend (To-Do app interface)<strong>:</strong> <strong>http://localhost:5173</strong></p>
</li>
<li><p>Backend (Stored tasks in the database)<strong>:</strong> <strong>http://localhost:5000/api/tasks</strong></p>
</li>
</ul>
<p>Test the functionality by adding, editing, saving, deleting tasks, and checking off completed tasks to ensure everything works properly.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You have successfully built a MERN To-Do app. You can further enhance it by adding features such as time and date tracking, and deploying it to a cloud platform.</p>
<p>Feel free to copy the code or clone the <a target="_blank" href="https://github.com/nuelcas/mern-todo-app.git">GitHub</a> repository to add more functionalities and customize the styling to your preference. If you found this guide helpful, please consider sharing it and <a target="_blank" href="https://www.linkedin.com/in/casmir-onyekani/">connecting</a> with me!</p>
<p>For more learning resources:</p>
<ul>
<li><p><a target="_blank" href="https://react.dev/">React.js Docs</a></p>
</li>
<li><p><a target="_blank" href="https://www.typescriptlang.org/">TypeScript Docs</a></p>
</li>
<li><p><a target="_blank" href="https://vite.dev/">Vite Docs</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/docs/">MongoDB Docs</a></p>
</li>
<li><p><a target="_blank" href="https://nodejs.org/docs/latest/api/">Node.js Docs</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Tests Using the Node.js Test Runner and mongodb-memory-server ]]>
                </title>
                <description>
                    <![CDATA[ I recently migrated some tests from Jest to the Node.js test runner in two of my projects that use MongoDB. In one of those projects, test runtime was reduced from 107 seconds to 25 seconds (screenshot below). In the other project, test runtime was r... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-tests-using-the-nodejs-test-runner-and-mongodb-memory-server/</link>
                <guid isPermaLink="false">67ae1ed03cb7bcfa7a1a3530</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Orim Dominic Adah ]]>
                </dc:creator>
                <pubDate>Thu, 13 Feb 2025 16:33:20 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739464298236/f5d6c959-4570-4813-bdd2-28c27dae4e1f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I recently migrated some tests from Jest to the Node.js test runner in two of my projects that use MongoDB. In one of those projects, test runtime was reduced from 107 seconds to 25 seconds (screenshot below). In the other project, test runtime was reduced by about 66%.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738830673460/1560f7a3-38c1-42f3-8944-df06b40d73e4.png" alt="76% reduction in time taken to run tests in Jest vs Node.js test runner" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>I decided to share with you how I was able to implement this. I think you’ll find it helpful, as it’s more cost-effective (in terms of reducing money spent on running tests in CI/CD), and it also improves your developer experience.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-nodejs-test-runner">The Node.js Test Runner</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-mongodb-in-memory-server">MongoDB In-Memory Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-write-the-tests">How to Write the Tests</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-set-up-the-project">1. Set Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-set-up-mongoose-schema">2. Set up Mongoose Schema</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-set-up-services">3. Set Up Services</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-4-set-up-tests">4. Set Up Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-5-write-tests">5. Write Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-6-pass-tests">6. Pass Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-7-use-typescript-optional">7. Use TypeScript (Optional)</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this guide, you should have experience working with Node.js, MongoDB, and Mongoose (or any other MongoDB object data mapper). You should also have Node.js (at least v20.18.2) and MongoDB installed on your computer.</p>
<h2 id="heading-the-nodejs-test-runner">The Node.js Test Runner</h2>
<p>The Node.js test runner was introduced as an experimental feature in version 18 of Node.js. It became fully available in version 20. It gives you the ability to:</p>
<ol>
<li><p>Run tests</p>
</li>
<li><p>Report test results</p>
</li>
<li><p>Report test coverage (still experimental at version 23)</p>
</li>
</ol>
<p>It’s a good idea to use the in-built test runner when writing tests in Node.js because it means that you have to use fewer external dependencies. You don’t need to install an external library (and its peer dependencies) to run tests.</p>
<p>The built-in best runner is also faster. Based on my experience using it on two projects (which formerly used Jest), I saw improvements of at least a 66% reduction in the time taken to run tests completely.</p>
<p>And unlike other testing frameworks or libraries, the Node.js test runner was built specifically for Node.js projects. It doesn’t try to accommodate the specifics of other programming environments like the browser. The specifics of Node.js are its main and only priority.</p>
<h2 id="heading-mongodb-in-memory-server">MongoDB In-Memory Server</h2>
<p>For tests that involve making requests to a database, some developers prefer to mock the requests to avoid making requests to a real database. They do this because making a request to a real database requires a lot of setting up which can cost time and resources.</p>
<p>Writing and fetching data using a real database is slower <a target="_blank" href="https://www.mongodb.com/resources/basics/databases/in-memory-database">compared to writing and fetching data from memory</a>. When running automated tests, using a real MongoDB server will be slower than using an in-memory database server, and that is where <a target="_blank" href="https://github.com/typegoose/mongodb-memory-server">mongodb-memory-server</a> becomes useful.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738832586702/62360547-70e8-4e74-854f-c7ad74d182ea.png" alt="Comparison between memory and database communication with CPU" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>According to its documentation, mongodb-memory-server creates and starts a real MongoDB server programmatically from within Node.js, but uses an in-memory database by default. It also allows you to connect to the database server it creates using your preferred object data mapper such as Mongoose, Prisma, or TypeORM. In this guide, we’ll use <a target="_blank" href="https://mongoosejs.com/">Mongoose</a> (v8.9.6).</p>
<p>Since the data stored by mongodb-memory-server resides in memory by default, it’s faster to read from and write to than when using a real database. mongodb-memory-server is also easier to set up. These benefits make it a good choice for using it as a database server for writing tests.</p>
<p>Note: Make sure to install v9.1.6 of mongodb-memory-server to follow this guide. v10 currently has issues with cleaning up resources after tests are done. See this issue titled <a target="_blank" href="https://github.com/typegoose/mongodb-memory-server/issues/912">Node forking will include any --import from the original command</a>.</p>
<p>The issue has been resolved at the time of writing this article, but the fix has not been merged for installs.</p>
<h2 id="heading-how-to-write-the-tests">How to Write the Tests</h2>
<p>Now I’ll take you through the following steps to get you started writing tests:</p>
<ol>
<li><p>Set up the project</p>
</li>
<li><p>Set up mongoose schema</p>
</li>
<li><p>Set up services</p>
</li>
<li><p>Set up tests</p>
</li>
<li><p>Write tests</p>
</li>
<li><p>Pass tests</p>
</li>
<li><p>Use TypeScript (Optional)</p>
</li>
</ol>
<h3 id="heading-1-set-up-the-project">1. Set Up the Project</h3>
<p>I created a GitHub repository to make it easier for you to follow this guide. Clone the repository at <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose">nodejs-test-runner-mongoose</a> and checkout branch <code>01-setup</code>.</p>
<p>In <code>01-setup</code>, the dependencies for the project are in the <code>package.json</code> file. Install the dependencies using the <code>npm install</code> command to set up the project. To make sure that the setup is complete and correct, run the <code>node .</code> command in the terminal of your project. You should see your version of Node.js as an output on the terminal.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># install dependencies</span>
npm install
...
<span class="hljs-comment"># run the node command</span>
node .
<span class="hljs-comment"># the output</span>
You are running Node.js v22.13.1
</code></pre>
<h3 id="heading-2-set-up-mongoose-schema">2. Set up Mongoose Schema</h3>
<p>We’ll set up the schema for two collections (Task and User) in branch <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/tree/02-setup-schema"><code>02-setup-schema</code></a> using Mongoose. The <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/blob/02-setup-schema/task/model.mjs"><code>task/model.mjs</code></a> and <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/blob/02-setup-schema/user/model.mjs"><code>user/model.mjs</code></a> files contain the schema for the Task and the User collection, respectively. We’ll also set up a database connection in <code>index.mjs</code> to ensure that the schema setup works correctly.</p>
<p>I won’t go into detail about Mongoose models and schema in this article because they are outside its scope.</p>
<p>When you run the <code>node .</code> command after implementing the changes in <code>02-setup-schema</code>, you should see a similar result in the console as in the snippet below:</p>
<pre><code class="lang-bash">node .
You are running Node.js v22.13.1
Created user with id 679f1d7f73fbeaf23b2007df
Created task <span class="hljs-string">"Task title"</span> <span class="hljs-keyword">for</span> user with id <span class="hljs-string">"679f1d7f73fbeaf23b2007df"</span>
</code></pre>
<p>You can see the differences between <code>01-setup</code> and <code>02-setup-schema</code> via the <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/01-setup...02-setup-schema">01-setup &lt;&gt; 02-setup-schema diff on GitHub</a>.</p>
<h3 id="heading-3-set-up-services">3. Set Up Services</h3>
<p>Next, we create service files (<a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/blob/03-setup-services/task/service.mjs"><code>task/service.mjs</code></a> and <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/blob/03-setup-services/user/service.mjs"><code>user/service.mjs</code></a>) in branch <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/tree/03-setup-services"><code>03-setup-services</code></a>. Both files currently contain empty functions that we’ll write tests for later. These functions will contain business logic and also communicate with the database. We’re using <a target="_blank" href="https://jsdoc.app/">JSDoc</a> comments for typing parameters and return values.</p>
<p>Click <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/01-setup...02-setup-schema">02-setup-schema &lt;&gt; 03-setup-services diff</a> to see the code changes between <code>02-setup-schema</code> and <code>03-setup-services</code>.</p>
<h3 id="heading-4-set-up-tests">4. Set Up Tests</h3>
<p>In branch <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/tree/04-set-up-tests"><code>04-set-up-tests</code></a>, we set up the codebase to run tests. We create <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/blob/04-set-up-tests/test.setup.mjs"><code>test.setup.mjs</code></a> which contains code that will be run before each test file is executed.</p>
<p>In <code>test.setup.mjs</code>, the <code>connect</code> function creates a MongoDB In-Memory server and connects to it with Mongoose for running the tests. The <code>closeDatabase</code> function closes the database connection and cleans up all resources to free memory.</p>
<p>The <code>connect</code> and <code>closeDatabase</code> functions get executed in the <a target="_blank" href="https://nodejs.org/api/test.html#beforefn-options"><code>t.before</code></a> hook and the <a target="_blank" href="https://nodejs.org/api/test.html#afterfn-options"><code>t.after</code></a> hook respectively. This ensures that, before a test file is run, a database connection is established through <code>t.before</code>. Then after tests for the file have been completely run, the database connection is dropped and the resources used are cleared up through <code>t.after</code>.</p>
<p>In <code>package.json</code>, we’ll update the npm <code>test</code> script to <code>node --test --import ./test.setup.mjs</code>. This command ensures that the <code>test.setup.mjs</code> ES Module is preloaded and executed through the <a target="_blank" href="https://nodejs.org/api/cli.html#--importmodule">--import</a> CLI command before each test file is run.</p>
<p>Then we’ll create the test files with empty tests in the <code>__tests__</code> folders for <code>user</code> and <code>task</code>. After implementing the <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/03-setup-services...04-set-up-tests">new changes in 04-set-up-tests</a>, running the <code>test</code> script with <code>npm run test</code> should display output similar to the snippet below:</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span>

&gt; nodejs-test-runner-mongoose@1.0.0 <span class="hljs-built_in">test</span>
&gt; node --<span class="hljs-built_in">test</span> --import ./test.setup.mjs

...

ℹ tests 8
ℹ suites 5
ℹ pass 8
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 941.768873
</code></pre>
<p>All tests currently pass because there are no assertions that fail in them. We’ll write tests with assertions in the following section.</p>
<h3 id="heading-5-write-tests">5. Write Tests</h3>
<p>Now it’s time to write tests for the functions in the service files in the <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/blob/05-write-tests"><code>05-write-tests</code></a> branch. We’re using the <a target="_blank" href="https://nodejs.org/api/assert.html">Node.js assert library</a> to ensure that values returned from the functions are what we expect. You can view the tests we’ve written when you compare <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/04-set-up-tests...05-write-tests">the differences between 04-set-up-tests and 05-write-tests</a></p>
<p>When the <code>tests</code> script is run, all tests fail because we haven’t written the functions in the service files yet. You should see output similar to the snippet below when you run the <code>test</code> script:</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span>

&gt; nodejs-test-runner-mongoose@1.0.0 <span class="hljs-built_in">test</span>
&gt; node --<span class="hljs-built_in">test</span> --import ./test.setup.mjs

...

ℹ tests 8
ℹ suites 5
ℹ pass 0
ℹ fail 8
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1202.031961
</code></pre>
<h3 id="heading-6-pass-tests">6. Pass Tests</h3>
<p>In <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/blob/06-pass-tests"><code>06-pass-tests</code></a>, we write the functions in the service files to pass the tests. Only 6 out of 7 tests pass when the <code>test</code> script is run because we skipped the test for the <code>getById</code> function in <code>user/service.mjs</code> has with <code>t.skip</code>. We haven’t finished the <code>getById</code> function in <code>user/service.mjs</code>. I figured we could leave it as an exercise.</p>
<p>When you run the <code>test</code> script, you should get a similar output in the terminal as below:</p>
<pre><code class="lang-bash">ℹ tests 7
ℹ suites 4
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 1
ℹ todo 0
ℹ duration_ms 1287.564918
</code></pre>
<p>You can see the code we wrote to pass tests in the <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/05-write-tests...06-pass-tests">code changes between 05-write-tests and 06-pass-tests</a>.</p>
<h3 id="heading-7-use-typescript-optional">7. Use TypeScript (Optional)</h3>
<p>If you intend to run tests with TypeScript, you can checkout branch <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/tree/07-with-typescript"><code>07-with-typescript</code></a>. You need to have Node.js <code>&gt;=v22.6.0</code> installed because we’re using the <code>--experimental-strip-types</code> option in the <code>test</code>. To set up tests to run with TypeScript, go through the following steps:</p>
<ol>
<li><p>Install TypeScript using the <code>npm install typescript --save-dev</code> command</p>
</li>
<li><p>Install tsx using the <code>npm install tsx</code> command</p>
</li>
<li><p>Create a default <code>tsconfig.json</code> file at the root of the project using the <code>npx tsc --init</code> command</p>
</li>
</ol>
<p>In <code>package.json</code>, update the <code>test</code> script to this:</p>
<pre><code class="lang-bash"><span class="hljs-string">"test"</span>: <span class="hljs-string">"node --test --experimental-strip-types --import tsx --import ./test.setup.mjs"</span>
</code></pre>
<ul>
<li><p><a target="_blank" href="https://nodejs.org/docs/latest-v22.x/api/cli.html#--experimental-strip-types"><code>--experimental-strip-types</code></a> helps strip out types before each test file is executed.</p>
</li>
<li><p>Preloading <code>tsx</code> with the <code>--import</code> helps execute the TypeScript file. Without it, the test runner will not be able to find files imported without the <code>.ts</code> extension. For example, <code>user/model.ts</code> imported with the code snippet below will not be found.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">import</span> { UserModel } <span class="hljs-keyword">from</span> <span class="hljs-string">"./model"</span>;
</code></pre>
</li>
</ul>
<p>The rest of the <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/06-pass-tests...07-with-typescript">changes from 06-pass-tests to 07-with-typescript</a> involve updating types, changing file extensions from <code>.mjs</code> to <code>.ts</code> and updating import statements.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, you have learned how to use the built-in Node.js test runner and why it’s often a better choice over other testing libraries and frameworks. You have also learned how to use mongodb-memory-server as a replacement for a real MongoDB server, as well as why it’s a good idea to use this instead of a real MongoDB server for tests.</p>
<p>Most importantly, you have learned how to set up and run tests in Node.js using the Node.js test runner and mongodb-memory-server. You should now know how to set up your projects to run the tests if you use TypeScript.</p>
<p>If you find the <a target="_blank" href="https://github.com/orimdominic/nodejs-test-runner-mongoose">nodejs-test-runner-mongoose</a> repository useful, kindly give it a star. It encourages me. Thank you.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Handle MongoDB Migrations with ts-migrate-mongoose ]]>
                </title>
                <description>
                    <![CDATA[ Database migrations are modifications made to a database. These modifications may include changing the schema of a table, updating the data in a set of records, seeding data or deleting a range of records. Database migrations are usually run before a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/handle-mongodb-migrations-with-ts-migrate-mongoose/</link>
                <guid isPermaLink="false">6747274cb7666002fd1cb1a6</guid>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Orim Dominic Adah ]]>
                </dc:creator>
                <pubDate>Wed, 27 Nov 2024 14:06:04 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732615343335/0a1b3e5e-bfa7-4f57-81a7-7f4bac9e8b0a.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Database migrations are modifications made to a database. These modifications may include changing the schema of a table, updating the data in a set of records, seeding data or deleting a range of records.</p>
<p>Database migrations are usually run before an application starts and do not run successfully more than once for the same database. Database migration tools save a history of migrations that have run in a database so that they can be tracked for future purposes.</p>
<p>In this article, you’ll learn how to set up and run database migrations in a minimal Node.js API application. We will use <a target="_blank" href="https://www.npmjs.com/package/ts-migrate-mongoose">ts-migrate-mongoose</a> and an npm script to create a migration and seed data into a MongoDB database. ts-migrate-mongoose supports running migration scripts from TypeScript code as well as CommonJS code.</p>
<p>ts-migrate-mongoose is a migration framework for Node.js projects that use <a target="_blank" href="https://www.npmjs.com/package/mongoose">mongoose</a> as the object-data mapper. It provides a template for writing migration scripts. It also provides a configuration to run the scripts programmatically and from the CLI.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-project">How to Set Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-ts-migrate-mongoose-for-the-project">How to Configure ts-migrate-mongoose for the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-seed-user-data-with-ts-migrate-mongoose">How to Seed User Data with ts-migrate-mongoose</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-an-api-endpoint-to-fetch-seeded-data">How to Build an API Endpoint to Fetch Seeded Data</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</h2>
<p>To use ts-migrate-mongoose for database migrations, you need to have the following:</p>
<ol>
<li><p>A Node.js project with mongoose installed as a dependency.</p>
</li>
<li><p>A MongoDB database connected to the project.</p>
</li>
<li><p>MongoDB Compass (Optional – to enable us view the changes in the database).</p>
</li>
</ol>
<p>A starter repository which can be cloned from <a target="_blank" href="https://github.com/orimdominic/ts-migrate-mongoose-starter-repo">ts-migrate-mongoose-starter-repo</a> has been created for ease. Clone the repository, fill the environment variables and start the application by running the <code>npm start</code> command.</p>
<p>Visit <a target="_blank" href="http://localhost:8000">http://localhost:8000</a> with a browser or an API client such as Postman and the server will return a "Hello there!" text to show that the starter application runs as expected.</p>
<h2 id="heading-how-to-configure-ts-migrate-mongoose-for-the-project">How to Configure ts-migrate-mongoose for the Project</h2>
<p>To configure ts-migrate-mongoose for the project, install ts-migrate-mongoose with this command:</p>
<pre><code class="lang-bash">npm install ts-migrate-mongoose
</code></pre>
<p>ts-migrate-mongoose allows configuration with a JSON file, a TypeScript file, a <code>.env</code> file or via the CLI. It is advisable to use a <code>.env</code> file because the content of the configuration may contain a database password and it is not proper to have that exposed to the public. <code>.env</code> files are usually hidden via <code>.gitignore</code> files so they are more secure to use. This project will use a <code>.env</code> file for the ts-migrate-mongoose configuration.</p>
<p>The file should contain the following keys and their values:</p>
<ul>
<li><p><code>MIGRATE_MONGO_URI</code> - the URI of the Mongo database. It is the same as the database URL.</p>
</li>
<li><p><code>MIGRATE_MONGO_COLLECTION</code> - the name of the collection (or table) which migrations should be saved in. The default value is migrations which is what is used in this project. ts-migrate-mongoose saves migrations to MongoDB.</p>
</li>
<li><p><code>MIGRATE_MIGRATIONS_PATH</code> - the path to the folder for storing and reading migration scripts. The default value is <code>./migrations</code> which is what is used in this project.</p>
</li>
</ul>
<h2 id="heading-how-to-seed-user-data-with-ts-migrate-mongoose">How to Seed User Data with ts-migrate-mongoose</h2>
<p>We have been able to create a project and connect it successfully to a Mongo database. At this point, we want to seed user data into the database. We need to:</p>
<ol>
<li><p>Create a users collection (or table)</p>
</li>
<li><p>Use ts-migrate-mongoose to create a migration script to seed data</p>
</li>
<li><p>Use ts-migrate-mongoose to run the migration to seed the user data into the database before the application starts</p>
</li>
</ol>
<h3 id="heading-1-create-a-users-collection-using-mongoose">1. Create a users Collection using Mongoose</h3>
<p>Mongoose schema can be used to create a user collection (or table). User documents (or records) will have the following fields (or columns): <code>email</code>, <code>favouriteEmoji</code> and <code>yearOfBirth</code>.</p>
<p>To create a Mongoose schema for the user collection, create a <code>user.model.js</code> file in the root of the project containing the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);

<span class="hljs-keyword">const</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema(
  {
    <span class="hljs-attr">email</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">lowercase</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">favouriteEmoji</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">yearOfBirth</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
  },
  {
    <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span>,
  }
);

<span class="hljs-built_in">module</span>.exports.UserModel = mongoose.model(<span class="hljs-string">"User"</span>, userSchema);
</code></pre>
<h3 id="heading-2-create-a-migration-script-with-ts-migrate-mongoose">2. Create a Migration Script with ts-migrate-mongoose</h3>
<p>ts-migrate-mongoose provides CLI commands which can be used to create migration scripts.</p>
<p>Running <code>npx migrate create &lt;name-of-script&gt;</code> in the root folder of the project will create a script in the <code>MIGRATE_MIGRATIONS_PATH</code> folder (<code>./migrations</code> in our case). <code>&lt;name-of-script&gt;</code> is the name we want the migration script file to have when it is created.</p>
<p>To create a migration script to seed user data, run:</p>
<pre><code class="lang-bash">npx migrate create seed-users
</code></pre>
<p>The command will create a file in the <code>./migrations</code> folder with a name in the form -<code>&lt;timestamp&gt;-seed-users.ts</code>. The file will have the following code snippet content:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Import your models here</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span> (<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt; </span>{
  <span class="hljs-comment">// Write migration here</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">down</span> (<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt; </span>{
  <span class="hljs-comment">// Write migration here</span>
}
</code></pre>
<p>The <code>up</code> function is used to run the migration. The <code>down</code> function is used to reverse whatever the <code>up</code> function executes, if need be. In our case, we are trying to seed users into the database. The <code>up</code> function will contain code to seed users into the database and the <code>down</code> function will contain code to delete users created in the <code>up</code> function.</p>
<p>If the database is inspected with MongoDB Compass, the migrations collection will have a document that looks like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"_id"</span>: ObjectId(<span class="hljs-string">"6744740465519c3bd9c1a7d1"</span>),
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"seed-users"</span>,
  <span class="hljs-attr">"state"</span>: <span class="hljs-string">"down"</span>,
  <span class="hljs-attr">"createdAt"</span>: <span class="hljs-number">2024</span><span class="hljs-number">-11</span><span class="hljs-number">-25</span>T12:<span class="hljs-number">56</span>:<span class="hljs-number">36.316</span>+<span class="hljs-number">00</span>:<span class="hljs-number">00</span>,
  <span class="hljs-attr">"updatedAt"</span>: <span class="hljs-number">2024</span><span class="hljs-number">-11</span><span class="hljs-number">-25</span>T12:<span class="hljs-number">56</span>:<span class="hljs-number">36.316</span>+<span class="hljs-number">00</span>:<span class="hljs-number">00</span>,
  <span class="hljs-attr">"__v"</span>: <span class="hljs-number">0</span>
}
</code></pre>
<p>The <code>state</code> field of the migration document is set to <code>down</code>. After it runs successfully, it changes to <code>up</code>.</p>
<p>You can update the code in <code>./migrations/&lt;timestamp&gt;-seed-users.ts</code> to the one in the snippet below:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config() <span class="hljs-comment">// load env variables</span>
<span class="hljs-keyword">const</span> db = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../db.js"</span>)
<span class="hljs-keyword">const</span> { UserModel } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../user.model.js"</span>);

<span class="hljs-keyword">const</span> seedUsers = [
  { email: <span class="hljs-string">"john@email.com"</span>, favouriteEmoji: <span class="hljs-string">"🏃"</span>, yearOfBirth: <span class="hljs-number">1997</span> },
  { email: <span class="hljs-string">"jane@email.com"</span>, favouriteEmoji: <span class="hljs-string">"🍏"</span>, yearOfBirth: <span class="hljs-number">1998</span> },
];

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span> (<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt; </span>{
  <span class="hljs-keyword">await</span> db.connect(process.env.MONGO_URI)
  <span class="hljs-keyword">await</span> UserModel.create(seedUsers);}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">down</span> (<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">void</span>&gt; </span>{
  <span class="hljs-keyword">await</span> db.connect(process.env.MONGO_URI)
  <span class="hljs-keyword">await</span> UserModel.delete({
    email: {
      $in: seedUsers.map(<span class="hljs-function">(<span class="hljs-params">u</span>) =&gt;</span> u.email),
    },
  });
}
</code></pre>
<h3 id="heading-3-run-the-migration-before-the-application-starts">3. Run the Migration Before the Application Starts</h3>
<p>ts-migrate-mongoose provides us with CLI commands to run the <code>up</code> and <code>down</code> function of migration scripts.</p>
<p>With <code>npx migrate up &lt;name-of-script&gt;</code> we can run the <code>up</code> function of a specific script. With <code>npx migrate up</code> we can run the <code>up</code> function of all scripts in the <code>./migrations</code> folder with a <code>state</code> of <code>down</code> in the database.</p>
<p>To run the migration before the application starts, we make use of npm scripts. npm scripts with a prefix of <code>pre</code> will run before a script without the <code>pre</code> prefix. For example, if there is a <code>dev</code> script and a <code>predev</code> script, whenever the <code>dev</code> script is run with <code>npm run dev</code>, the <code>predev</code> script will automatically run before the <code>dev</code> script is run.</p>
<p>We will use this feature of npm scripts to place the ts-migrate-mongoose command in a <code>prestart</code> script so that the migration will run before the <code>start</code> script.</p>
<p>Update the <code>package.json</code> file to have a <code>prestart</code> script that runs the ts-migrate-mongoose command for running the <code>up</code> function of migration scripts in the project.</p>
<pre><code class="lang-json">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"prestart"</span>: <span class="hljs-string">"npx migrate up"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"node index.js"</span>
  },
</code></pre>
<p>With this setup, when <code>npm run start</code> is executed to start the application, the <code>prestart</code> script will run to execute the migration using ts-migrate-mongoose and seed the database before the application starts.</p>
<p>You should have something similar to the snippet below after running <code>npm run start</code>:</p>
<pre><code class="lang-bash">Synchronizing database with file system migrations...
MongoDB connection successful
up: 1732543529744-seed-users.ts 
All migrations finished successfully

&gt; ts-migrate-mongoose-starter-repo@1.0.0 start
&gt; node index.js

MongoDB connection successful                      
Server listening on port 8000
</code></pre>
<p>Check out the <a target="_blank" href="https://github.com/orimdominic/ts-migrate-mongoose-starter-repo/tree/seed-users">seed-users</a> branch of the repository to see the current status of the codebase at this point in the article.</p>
<h2 id="heading-how-to-build-an-api-endpoint-to-fetch-seeded-data">How to Build an API Endpoint to Fetch Seeded Data</h2>
<p>We can build an API endpoint to fetch the seeded users data in our database. In the <code>server.js</code> file, update the code to the one in the snippet below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { UserModel } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./user.model.js"</span>)

<span class="hljs-built_in">module</span>.exports = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">const</span> users = <span class="hljs-keyword">await</span> UserModel.find({}) <span class="hljs-comment">// fetch all the users in the database</span>

  res.writeHead(<span class="hljs-number">200</span>, { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> });
  <span class="hljs-keyword">return</span> res.end(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-comment">// return a JSON representation of the fetched users data</span>
    <span class="hljs-attr">users</span>: users.map(<span class="hljs-function">(<span class="hljs-params">u</span>) =&gt;</span> ({
      <span class="hljs-attr">email</span>: u.email,
      <span class="hljs-attr">favouriteEmoji</span>: u.favouriteEmoji,
      <span class="hljs-attr">yearOfBirth</span>: u.yearOfBirth,
      <span class="hljs-attr">createdAt</span>: u.createdAt
    }))
  }, <span class="hljs-literal">null</span>, <span class="hljs-number">2</span>));
};
</code></pre>
<p>If we start the application and visit <a target="_blank" href="http://localhost:8000">http://localhost:8000</a> using Postman or a browser, we get a JSON response similar to the one below:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"users"</span>: [
    {
      <span class="hljs-attr">"email"</span>: <span class="hljs-string">"john@email.com"</span>,
      <span class="hljs-attr">"favouriteEmoji"</span>: <span class="hljs-string">"🏃"</span>,
      <span class="hljs-attr">"yearOfBirth"</span>: <span class="hljs-number">1997</span>,
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2024-11-25T14:18:55.416Z"</span>
    },
    {
      <span class="hljs-attr">"email"</span>: <span class="hljs-string">"jane@email.com"</span>,
      <span class="hljs-attr">"favouriteEmoji"</span>: <span class="hljs-string">"🍏"</span>,
      <span class="hljs-attr">"yearOfBirth"</span>: <span class="hljs-number">1998</span>,
      <span class="hljs-attr">"createdAt"</span>: <span class="hljs-string">"2024-11-25T14:18:55.416Z"</span>
    }
  ]
}
</code></pre>
<p>Notice that if the application is run again, the migration script does not run anymore because the <code>state</code> of the migration will now be <code>up</code> after it has run successfully.</p>
<p>Check out the <a target="_blank" href="https://github.com/orimdominic/ts-migrate-mongoose-starter-repo/tree/fetch-users">fetch-users</a> branch of the repository to see the current status of the codebase at this point in the article.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Migrations are useful when building applications and there is need to seed initial data for testing, seeding administrative users, updating database schema by adding or removing columns and updating the values of columns in many records at once.</p>
<p>ts-migrate-mongoose can help provide a framework for running migrations for your Node.js applications if you use Mongoose with MongoDB.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Use the FARM Stack to Develop Full Stack Apps ]]>
                </title>
                <description>
                    <![CDATA[ The FARM stack is a modern web development stack that combines three powerful technologies: FastAPI, React, and MongoDB. This full-stack solution provides developers with a robust set of tools to build scalable, efficient, and high-performance web ap... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/use-the-farm-stack-to-develop-full-stack-apps/</link>
                <guid isPermaLink="false">66eadbde43610a404a1d5ab9</guid>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ FastAPI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 18 Sep 2024 13:55:42 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726760870442/726967ee-7f01-432d-a73e-9f73f037f942.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The FARM stack is a modern web development stack that combines three powerful technologies: FastAPI, React, and MongoDB. This full-stack solution provides developers with a robust set of tools to build scalable, efficient, and high-performance web applications.</p>
<p>In this article, I'll be giving you an introduction to each of the key technologies, and then we'll build a project using the FARM stack and Docker so you can see how everything works together.</p>
<p>This article is based on a course I created <a target="_blank" href="https://www.youtube.com/watch?v=PWG7NlUDVaA">on the freeCodeCamp.org YouTube channel</a>. Watch it here:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/PWG7NlUDVaA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h1 id="heading-introduction-to-the-farm-stack">Introduction to the FARM Stack</h1>
<p>The FARM in FARM stack stands for:</p>
<ul>
<li><p>F: FastAPI (Backend)</p>
</li>
<li><p>R: React (Frontend)</p>
</li>
<li><p>M: MongoDB (Database)</p>
</li>
</ul>
<p>The FARM stack is designed to leverage the strengths of each component, allowing developers to create feature-rich applications with a smooth development experience.</p>
<h3 id="heading-components-of-farm-stack">Components of FARM Stack</h3>
<ol>
<li><p><strong>FastAPI:</strong> FastAPI is a modern, high-performance Python web framework for building APIs. It's designed to be easy to use, fast to code, and ready for production environments. FastAPI is built on top of Starlette for the web parts and Pydantic for the data parts, making it a powerful choice for building robust backend services.</p>
</li>
<li><p><strong>React</strong>: React is a popular JavaScript library for building user interfaces. Developed and maintained by Facebook, React allows developers to create reusable UI components that efficiently update and render as data changes. Its component-based architecture and virtual DOM make it an excellent choice for building dynamic and responsive frontend applications.</p>
</li>
<li><p><strong>MongoDB:</strong> MongoDB is a document-oriented NoSQL database. It stores data in flexible, JSON-like documents, meaning fields can vary from document to document and data structure can be changed over time. This flexibility makes MongoDB an ideal choice for applications that need to evolve quickly and handle diverse data types.</p>
</li>
</ol>
<h3 id="heading-advantages-of-using-farm-stack">Advantages of using FARM Stack</h3>
<ol>
<li><p>High Performance: FastAPI is one of the fastest Python frameworks available, while React's virtual DOM ensures efficient UI updates. MongoDB's document model allows for quick reads and writes.</p>
</li>
<li><p>Scalability: All components of the FARM stack are designed to scale. FastAPI can handle concurrent requests efficiently, React applications can manage complex UIs, and MongoDB can distribute data across multiple servers.</p>
</li>
<li><p>Community and Ecosystem: All three technologies have large, active communities and rich ecosystems of libraries and tools.</p>
</li>
<li><p>Flexibility: The FARM stack is flexible enough to accommodate various types of web applications, from simple CRUD apps to complex, data-intensive systems.</p>
</li>
</ol>
<p>By combining these technologies, the FARM stack provides a comprehensive solution for building modern web applications. It allows developers to create fast, scalable backends with FastAPI, intuitive and responsive frontends with React, and flexible, efficient data storage with MongoDB. This stack is particularly well-suited for applications that require real-time updates, complex data models, and high performance.</p>
<h1 id="heading-project-overview-todo-application">Project Overview: Todo Application</h1>
<p>In the video course, I cover more about each individual technology in the FARM Stack. But in this article, we are going to jump right into a project to put everything together.</p>
<p>We will be creating a todo application to help us understand the FARM stack. Before we start creating the applicaiton, let’s discuss more about the features and software architecture.</p>
<h3 id="heading-features-of-the-todo-application">Features of the todo application</h3>
<p>Our FARM stack todo application will include the following features:</p>
<ol>
<li><p>Multiple Todo Lists:</p>
<ul>
<li><p>Users can create, view, update, and delete multiple todo lists.</p>
</li>
<li><p>Each list has a name and contains multiple todo items.</p>
</li>
</ul>
</li>
<li><p>Todo Items:</p>
<ul>
<li><p>Within each list, users can add, view, update, and delete todo items.</p>
</li>
<li><p>Each item has a label, a checked/unchecked status, and belongs to a specific list.</p>
</li>
</ul>
</li>
<li><p>Real-time Updates:</p>
<ul>
<li>The UI updates in real-time when changes are made to lists or items.</li>
</ul>
</li>
<li><p>Responsive Design:</p>
<ul>
<li>The application will be responsive and work well on both desktop and mobile devices.</li>
</ul>
</li>
</ol>
<h3 id="heading-system-architecture">System architecture</h3>
<p>Our todo application will follow a typical FARM stack architecture:</p>
<ol>
<li><p>Frontend (React):</p>
<ul>
<li><p>Provides the user interface for interacting with todo lists and items.</p>
</li>
<li><p>Communicates with the backend via RESTful API calls.</p>
</li>
</ul>
</li>
<li><p>Backend (FastAPI):</p>
<ul>
<li><p>Handles API requests from the frontend.</p>
</li>
<li><p>Implements business logic for managing todo lists and items.</p>
</li>
<li><p>Interacts with the MongoDB database for data persistence.</p>
</li>
</ul>
</li>
<li><p>Database (MongoDB):</p>
<ul>
<li><p>Stores todo lists and items.</p>
</li>
<li><p>Provides efficient querying and updating of todo data.</p>
</li>
</ul>
</li>
<li><p>Docker:</p>
<ul>
<li>Containerizes each component (frontend, backend, database) for easy development and deployment.</li>
</ul>
</li>
</ol>
<h3 id="heading-data-model-design">Data model design</h3>
<p>Our MongoDB data model will consist of two main structures:</p>
<ol>
<li>Todo List:</li>
</ol>
<pre><code class="lang-json">   {
     <span class="hljs-attr">"_id"</span>: ObjectId,
     <span class="hljs-attr">"name"</span>: String,
     <span class="hljs-attr">"items"</span>: [
       {
         <span class="hljs-attr">"id"</span>: String,
         <span class="hljs-attr">"label"</span>: String,
         <span class="hljs-attr">"checked"</span>: Boolean
       }
     ]
   }
</code></pre>
<ol start="2">
<li>List Summary (for displaying in the list of all todo lists):</li>
</ol>
<pre><code class="lang-json">   {
     <span class="hljs-attr">"_id"</span>: ObjectId,
     <span class="hljs-attr">"name"</span>: String,
     <span class="hljs-attr">"item_count"</span>: Integer
   }
</code></pre>
<h3 id="heading-api-endpoint-design">API endpoint design</h3>
<p>Our FastAPI backend will expose the following RESTful endpoints:</p>
<ol>
<li><p>Todo Lists:</p>
<ul>
<li><p>GET /api/lists: Retrieve all todo lists (summary view)</p>
</li>
<li><p>POST /api/lists: Create a new todo list</p>
</li>
<li><p>GET /api/lists/{list_id}: Retrieve a specific todo list with all its items</p>
</li>
<li><p>DELETE /api/lists/{list_id}: Delete a specific todo list</p>
</li>
</ul>
</li>
<li><p>Todo Items:</p>
<ul>
<li><p>POST /api/lists/{list_id}/items: Add a new item to a specific list</p>
</li>
<li><p>PATCH /api/lists/{list_id}/checked_state: Update the checked state of an item</p>
</li>
<li><p>DELETE /api/lists/{list_id}/items/{item_id}: Delete a specific item from a list</p>
</li>
</ul>
</li>
</ol>
<p>This project will provide a solid foundation in FARM stack development and Docker containerization, which you can then expand upon for more complex applications in the future.</p>
<p>So let's get started with the project.</p>
<h1 id="heading-project-tutorial">Project Tutorial</h1>
<h2 id="heading-project-setup-and-backend-development">Project Setup and Backend Development</h2>
<p>Step 1: Set up the project structure</p>
<p>Create a new directory for your project:</p>
<pre><code class="lang-csharp">   mkdir farm-stack-todo
   cd farm-stack-todo
</code></pre>
<p>Create subdirectories for the backend and frontend:</p>
<pre><code class="lang-csharp">   mkdir backend frontend
</code></pre>
<p>Step 2: Set up the backend environment</p>
<p>Navigate to the backend directory:</p>
<pre><code class="lang-csharp">   cd backend
</code></pre>
<p>Create a virtual environment and activate it:</p>
<pre><code class="lang-csharp">   python -m venv venv
   source venv/bin/activate  <span class="hljs-meta"># On Windows, use: venv\Scripts\activate</span>
</code></pre>
<p>Create the following files in the backend directory:</p>
<ol start="3">
<li><ul>
<li><p>Dockerfile</p>
<ul>
<li>pyproject.toml</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>    In your terminal, install the required packages:</p>
<pre><code class="lang-powershell">pip install <span class="hljs-string">"fastapi[all]"</span> <span class="hljs-string">"motor[srv]"</span> beanie aiostream
</code></pre>
<p>Generate the requirements.txt file:</p>
<pre><code class="lang-powershell">pip freeze &gt; requirements.txt
</code></pre>
<p>After creating the requirements.txt file (either through pip-compile or manually), you can install the dependencies using:</p>
<pre><code class="lang-csharp">   pip install -r requirements.txt
</code></pre>
<p>Add the following content to Dockerfile:</p>
<pre><code class="lang-csharp">   FROM python:<span class="hljs-number">3</span>

   WORKDIR /usr/src/app
   COPY requirements.txt ./

   RUN pip install --no-cache-dir --upgrade -r ./requirements.txt

   EXPOSE <span class="hljs-number">3001</span>

   CMD [ <span class="hljs-string">"python"</span>, <span class="hljs-string">"./src/server.py"</span> ]
</code></pre>
<p>Add the following content to pyproject.toml:</p>
<pre><code class="lang-csharp">   [<span class="hljs-meta">tool.pytest.ini_options</span>]
   pythonpath = <span class="hljs-string">"src"</span>
</code></pre>
<p>Step 4: Set up the backend structure</p>
<p>Create a src directory inside the backend directory:</p>
<pre><code class="lang-csharp">   mkdir src
</code></pre>
<p>Create the following files inside the src directory:</p>
<ol start="2">
<li><ul>
<li><p><a target="_blank" href="http://server.py">server.py</a></p>
<ul>
<li><a target="_blank" href="http://dal.py">dal.py</a></li>
</ul>
</li>
</ul>
</li>
</ol>
<p>Step 5: Implement the Data Access Layer (DAL)</p>
<p>Open src/<a target="_blank" href="http://dal.py">dal.py</a> and add the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> bson <span class="hljs-keyword">import</span> ObjectId
<span class="hljs-keyword">from</span> motor.motor_asyncio <span class="hljs-keyword">import</span> AsyncIOMotorCollection
<span class="hljs-keyword">from</span> pymongo <span class="hljs-keyword">import</span> ReturnDocument

<span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> BaseModel

<span class="hljs-keyword">from</span> uuid <span class="hljs-keyword">import</span> uuid4

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ListSummary</span>(<span class="hljs-params">BaseModel</span>):</span>
  id: str
  name: str
  item_count: int

<span class="hljs-meta">  @staticmethod</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_doc</span>(<span class="hljs-params">doc</span>) -&gt; "ListSummary":</span>
      <span class="hljs-keyword">return</span> ListSummary(
          id=str(doc[<span class="hljs-string">"_id"</span>]),
          name=doc[<span class="hljs-string">"name"</span>],
          item_count=doc[<span class="hljs-string">"item_count"</span>],
      )

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToDoListItem</span>(<span class="hljs-params">BaseModel</span>):</span>
  id: str
  label: str
  checked: bool

<span class="hljs-meta">  @staticmethod</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_doc</span>(<span class="hljs-params">item</span>) -&gt; "ToDoListItem":</span>
      <span class="hljs-keyword">return</span> ToDoListItem(
          id=item[<span class="hljs-string">"id"</span>],
          label=item[<span class="hljs-string">"label"</span>],
          checked=item[<span class="hljs-string">"checked"</span>],
      )

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToDoList</span>(<span class="hljs-params">BaseModel</span>):</span>
  id: str
  name: str
  items: list[ToDoListItem]

<span class="hljs-meta">  @staticmethod</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_doc</span>(<span class="hljs-params">doc</span>) -&gt; "ToDoList":</span>
      <span class="hljs-keyword">return</span> ToDoList(
          id=str(doc[<span class="hljs-string">"_id"</span>]),
          name=doc[<span class="hljs-string">"name"</span>],
          items=[ToDoListItem.from_doc(item) <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> doc[<span class="hljs-string">"items"</span>]],
      )

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToDoDAL</span>:</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, todo_collection: AsyncIOMotorCollection</span>):</span>
      self._todo_collection = todo_collection

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">list_todo_lists</span>(<span class="hljs-params">self, session=None</span>):</span>
      <span class="hljs-keyword">async</span> <span class="hljs-keyword">for</span> doc <span class="hljs-keyword">in</span> self._todo_collection.find(
          {},
          projection={
              <span class="hljs-string">"name"</span>: <span class="hljs-number">1</span>,
              <span class="hljs-string">"item_count"</span>: {<span class="hljs-string">"$size"</span>: <span class="hljs-string">"$items"</span>},
          },
          sort={<span class="hljs-string">"name"</span>: <span class="hljs-number">1</span>},
          session=session,
      ):
          <span class="hljs-keyword">yield</span> ListSummary.from_doc(doc)

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_todo_list</span>(<span class="hljs-params">self, name: str, session=None</span>) -&gt; str:</span>
      response = <span class="hljs-keyword">await</span> self._todo_collection.insert_one(
          {<span class="hljs-string">"name"</span>: name, <span class="hljs-string">"items"</span>: []},
          session=session,
      )
      <span class="hljs-keyword">return</span> str(response.inserted_id)

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_todo_list</span>(<span class="hljs-params">self, id: str | ObjectId, session=None</span>) -&gt; ToDoList:</span>
      doc = <span class="hljs-keyword">await</span> self._todo_collection.find_one(
          {<span class="hljs-string">"_id"</span>: ObjectId(id)},
          session=session,
      )
      <span class="hljs-keyword">return</span> ToDoList.from_doc(doc)

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete_todo_list</span>(<span class="hljs-params">self, id: str | ObjectId, session=None</span>) -&gt; bool:</span>
      response = <span class="hljs-keyword">await</span> self._todo_collection.delete_one(
          {<span class="hljs-string">"_id"</span>: ObjectId(id)},
          session=session,
      )
      <span class="hljs-keyword">return</span> response.deleted_count == <span class="hljs-number">1</span>

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_item</span>(<span class="hljs-params">
      self,
      id: str | ObjectId,
      label: str,
      session=None,
  </span>) -&gt; ToDoList | <span class="hljs-keyword">None</span>:</span>
      result = <span class="hljs-keyword">await</span> self._todo_collection.find_one_and_update(
          {<span class="hljs-string">"_id"</span>: ObjectId(id)},
          {
              <span class="hljs-string">"$push"</span>: {
                  <span class="hljs-string">"items"</span>: {
                      <span class="hljs-string">"id"</span>: uuid4().hex,
                      <span class="hljs-string">"label"</span>: label,
                      <span class="hljs-string">"checked"</span>: <span class="hljs-literal">False</span>,
                  }
              }
          },
          session=session,
          return_document=ReturnDocument.AFTER,
      )
      <span class="hljs-keyword">if</span> result:
          <span class="hljs-keyword">return</span> ToDoList.from_doc(result)

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_checked_state</span>(<span class="hljs-params">
      self,
      doc_id: str | ObjectId,
      item_id: str,
      checked_state: bool,
      session=None,
  </span>) -&gt; ToDoList | <span class="hljs-keyword">None</span>:</span>
      result = <span class="hljs-keyword">await</span> self._todo_collection.find_one_and_update(
          {<span class="hljs-string">"_id"</span>: ObjectId(doc_id), <span class="hljs-string">"items.id"</span>: item_id},
          {<span class="hljs-string">"$set"</span>: {<span class="hljs-string">"items.$.checked"</span>: checked_state}},
          session=session,
          return_document=ReturnDocument.AFTER,
      )
      <span class="hljs-keyword">if</span> result:
          <span class="hljs-keyword">return</span> ToDoList.from_doc(result)

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete_item</span>(<span class="hljs-params">
      self,
      doc_id: str | ObjectId,
      item_id: str,
      session=None,
  </span>) -&gt; ToDoList | <span class="hljs-keyword">None</span>:</span>
      result = <span class="hljs-keyword">await</span> self._todo_collection.find_one_and_update(
          {<span class="hljs-string">"_id"</span>: ObjectId(doc_id)},
          {<span class="hljs-string">"$pull"</span>: {<span class="hljs-string">"items"</span>: {<span class="hljs-string">"id"</span>: item_id}}},
          session=session,
          return_document=ReturnDocument.AFTER,
      )
      <span class="hljs-keyword">if</span> result:
          <span class="hljs-keyword">return</span> ToDoList.from_doc(result)
</code></pre>
<p>This concludes Part 1 of the tutorial, where we set up the project structure and implemented the Data Access Layer for our FARM stack todo application. In the next part, we'll implement the FastAPI server and create the API endpoints.</p>
<h2 id="heading-implementing-the-fastapi-server">Implementing the FastAPI Server</h2>
<p>Step 6: Implement the FastAPI server</p>
<p>Open src/<a target="_blank" href="http://server.py">server.py</a> and add the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> contextlib <span class="hljs-keyword">import</span> asynccontextmanager
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> sys

<span class="hljs-keyword">from</span> bson <span class="hljs-keyword">import</span> ObjectId
<span class="hljs-keyword">from</span> fastapi <span class="hljs-keyword">import</span> FastAPI, status
<span class="hljs-keyword">from</span> motor.motor_asyncio <span class="hljs-keyword">import</span> AsyncIOMotorClient
<span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> BaseModel
<span class="hljs-keyword">import</span> uvicorn

<span class="hljs-keyword">from</span> dal <span class="hljs-keyword">import</span> ToDoDAL, ListSummary, ToDoList

COLLECTION_NAME = <span class="hljs-string">"todo_lists"</span>
MONGODB_URI = os.environ[<span class="hljs-string">"MONGODB_URI"</span>]
DEBUG = os.environ.get(<span class="hljs-string">"DEBUG"</span>, <span class="hljs-string">""</span>).strip().lower() <span class="hljs-keyword">in</span> {<span class="hljs-string">"1"</span>, <span class="hljs-string">"true"</span>, <span class="hljs-string">"on"</span>, <span class="hljs-string">"yes"</span>}


<span class="hljs-meta">@asynccontextmanager</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">lifespan</span>(<span class="hljs-params">app: FastAPI</span>):</span>
    <span class="hljs-comment"># Startup:</span>
    client = AsyncIOMotorClient(MONGODB_URI)
    database = client.get_default_database()

    <span class="hljs-comment"># Ensure the database is available:</span>
    pong = <span class="hljs-keyword">await</span> database.command(<span class="hljs-string">"ping"</span>)
    <span class="hljs-keyword">if</span> int(pong[<span class="hljs-string">"ok"</span>]) != <span class="hljs-number">1</span>:
        <span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"Cluster connection is not okay!"</span>)

    todo_lists = database.get_collection(COLLECTION_NAME)
    app.todo_dal = ToDoDAL(todo_lists)

    <span class="hljs-comment"># Yield back to FastAPI Application:</span>
    <span class="hljs-keyword">yield</span>

    <span class="hljs-comment"># Shutdown:</span>
    client.close()


app = FastAPI(lifespan=lifespan, debug=DEBUG)


<span class="hljs-meta">@app.get("/api/lists")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_all_lists</span>() -&gt; list[ListSummary]:</span>
    <span class="hljs-keyword">return</span> [i <span class="hljs-keyword">async</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> app.todo_dal.list_todo_lists()]


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewList</span>(<span class="hljs-params">BaseModel</span>):</span>
    name: str


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewListResponse</span>(<span class="hljs-params">BaseModel</span>):</span>
    id: str
    name: str


<span class="hljs-meta">@app.post("/api/lists", status_code=status.HTTP_201_CREATED)</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_todo_list</span>(<span class="hljs-params">new_list: NewList</span>) -&gt; NewListResponse:</span>
    <span class="hljs-keyword">return</span> NewListResponse(
        id=<span class="hljs-keyword">await</span> app.todo_dal.create_todo_list(new_list.name),
        name=new_list.name,
    )


<span class="hljs-meta">@app.get("/api/lists/{list_id}")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_list</span>(<span class="hljs-params">list_id: str</span>) -&gt; ToDoList:</span>
    <span class="hljs-string">"""Get a single to-do list"""</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> app.todo_dal.get_todo_list(list_id)


<span class="hljs-meta">@app.delete("/api/lists/{list_id}")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete_list</span>(<span class="hljs-params">list_id: str</span>) -&gt; bool:</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> app.todo_dal.delete_todo_list(list_id)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewItem</span>(<span class="hljs-params">BaseModel</span>):</span>
    label: str


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewItemResponse</span>(<span class="hljs-params">BaseModel</span>):</span>
    id: str
    label: str


<span class="hljs-meta">@app.post(</span>
    <span class="hljs-string">"/api/lists/{list_id}/items/"</span>,
    status_code=status.HTTP_201_CREATED,
)
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_item</span>(<span class="hljs-params">list_id: str, new_item: NewItem</span>) -&gt; ToDoList:</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> app.todo_dal.create_item(list_id, new_item.label)


<span class="hljs-meta">@app.delete("/api/lists/{list_id}/items/{item_id}")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">delete_item</span>(<span class="hljs-params">list_id: str, item_id: str</span>) -&gt; ToDoList:</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> app.todo_dal.delete_item(list_id, item_id)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToDoItemUpdate</span>(<span class="hljs-params">BaseModel</span>):</span>
    item_id: str
    checked_state: bool


<span class="hljs-meta">@app.patch("/api/lists/{list_id}/checked_state")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_checked_state</span>(<span class="hljs-params">list_id: str, update: ToDoItemUpdate</span>) -&gt; ToDoList:</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> app.todo_dal.set_checked_state(
        list_id, update.item_id, update.checked_state
    )


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DummyResponse</span>(<span class="hljs-params">BaseModel</span>):</span>
    id: str
    when: datetime


<span class="hljs-meta">@app.get("/api/dummy")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_dummy</span>() -&gt; DummyResponse:</span>
    <span class="hljs-keyword">return</span> DummyResponse(
        id=str(ObjectId()),
        when=datetime.now(),
    )


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>(<span class="hljs-params">argv=sys.argv[<span class="hljs-number">1</span>:]</span>):</span>
    <span class="hljs-keyword">try</span>:
        uvicorn.run(<span class="hljs-string">"server:app"</span>, host=<span class="hljs-string">"0.0.0.0"</span>, port=<span class="hljs-number">3001</span>, reload=DEBUG)
    <span class="hljs-keyword">except</span> KeyboardInterrupt:
        <span class="hljs-keyword">pass</span>


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    main()
</code></pre>
<p>This implementation sets up the FastAPI server with CORS middleware, connects to MongoDB, and defines the API endpoints for our todo application.</p>
<p>Step 7: Set up environment variables</p>
<p>Create a .env file in the root directory with the following content. Make sure to add the database name ("todo") at the end of ".mongodb.net/".</p>
<pre><code class="lang-csharp">MONGODB_URI=<span class="hljs-string">'mongodb+srv://beau:codecamp@cluster0.ji7hu.mongodb.net/todo?retryWrites=true&amp;w=majority&amp;appName=Cluster0'</span>
</code></pre>
<p>Step 8: Create a docker-compose file</p>
<p>In the root directory of your project (farm-stack-todo), create a file named compose.yml with the following content:</p>
<pre><code class="lang-csharp">name: todo-app
services:
  nginx:
    image: nginx:<span class="hljs-number">1.17</span>
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/<span class="hljs-keyword">default</span>.conf
    ports:
      - <span class="hljs-number">8000</span>:<span class="hljs-number">80</span>
    depends_on:
      - backend
      - frontend
  frontend:
    image: <span class="hljs-string">"node:22"</span>
    user: <span class="hljs-string">"node"</span>
    working_dir: /home/node/app
    environment:
      - NODE_ENV=development
      - WDS_SOCKET_PORT=<span class="hljs-number">0</span>
    volumes:
      - ./frontend/:/home/node/app
    expose:
      - <span class="hljs-string">"3000"</span>
    ports:
      - <span class="hljs-string">"3000:3000"</span>
    command: <span class="hljs-string">"npm start"</span>
  backend:
    image: todo-app/backend
    build: ./backend
    volumes:
      - ./backend/:/usr/src/app
    expose:
      - <span class="hljs-string">"3001"</span>
    ports:
      - <span class="hljs-string">"8001:3001"</span>
    command: <span class="hljs-string">"python src/server.py"</span>
    environment:
      - DEBUG=<span class="hljs-literal">true</span>
    env_file:
      - path: ./.env
        required: <span class="hljs-literal">true</span>
</code></pre>
<p>Step 9: Set up Nginx configuration</p>
<p>Create a directory named nginx in the root of your project:</p>
<pre><code class="lang-csharp">mkdir nginx
</code></pre>
<p>Create a file named nginx.conf inside the nginx directory with the following content:</p>
<pre><code class="lang-python">server {
    listen <span class="hljs-number">80</span>;
    server_name farm_intro;

    location / {
        proxy_pass http://frontend:<span class="hljs-number">3000</span>;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection <span class="hljs-string">"upgrade"</span>;
    }

    location /api {
        proxy_pass http://backend:<span class="hljs-number">3001</span>/api;
    }
}
</code></pre>
<p>This concludes Part 2 of the tutorial, where we implemented the FastAPI server, set up environment variables, created a docker-compose file, and configured Nginx. In the next part, we'll focus on setting up the React frontend for our FARM stack todo application.</p>
<h1 id="heading-setting-up-the-react-frontend">Setting up the React Frontend</h1>
<p>Step 10: Create the React application</p>
<p>Navigate to the frontend directory:</p>
<pre><code class="lang-python">cd ../frontend
</code></pre>
<p>Create a new React application using Create React App:</p>
<pre><code class="lang-python">npx create-react-app .
</code></pre>
<p>Install additional dependencies:</p>
<pre><code class="lang-python">   npm install axios react-icons
</code></pre>
<p>Step 11: Set up the main App component</p>
<p>Replace the content of src/App.js with the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> ListToDoLists <span class="hljs-keyword">from</span> <span class="hljs-string">"./ListTodoLists"</span>;
<span class="hljs-keyword">import</span> ToDoList <span class="hljs-keyword">from</span> <span class="hljs-string">"./ToDoList"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [listSummaries, setListSummaries] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [selectedItem, setSelectedItem] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    reloadData().catch(<span class="hljs-built_in">console</span>.error);
  }, []);

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reloadData</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">"/api/lists"</span>);
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.data;
    setListSummaries(data);
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleNewToDoList</span>(<span class="hljs-params">newName</span>) </span>{
    <span class="hljs-keyword">const</span> updateData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> newListData = {
        <span class="hljs-attr">name</span>: newName,
      };

      <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">`/api/lists`</span>, newListData);
      reloadData().catch(<span class="hljs-built_in">console</span>.error);
    };
    updateData();
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleDeleteToDoList</span>(<span class="hljs-params">id</span>) </span>{
    <span class="hljs-keyword">const</span> updateData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">await</span> axios.delete(<span class="hljs-string">`/api/lists/<span class="hljs-subst">${id}</span>`</span>);
      reloadData().catch(<span class="hljs-built_in">console</span>.error);
    };
    updateData();
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleSelectList</span>(<span class="hljs-params">id</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Selecting item"</span>, id);
    setSelectedItem(id);
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">backToList</span>(<span class="hljs-params"></span>) </span>{
    setSelectedItem(<span class="hljs-literal">null</span>);
    reloadData().catch(<span class="hljs-built_in">console</span>.error);
  }

  <span class="hljs-keyword">if</span> (selectedItem === <span class="hljs-literal">null</span>) {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ListToDoLists</span>
          <span class="hljs-attr">listSummaries</span>=<span class="hljs-string">{listSummaries}</span>
          <span class="hljs-attr">handleSelectList</span>=<span class="hljs-string">{handleSelectList}</span>
          <span class="hljs-attr">handleNewToDoList</span>=<span class="hljs-string">{handleNewToDoList}</span>
          <span class="hljs-attr">handleDeleteToDoList</span>=<span class="hljs-string">{handleDeleteToDoList}</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ToDoList</span> <span class="hljs-attr">listId</span>=<span class="hljs-string">{selectedItem}</span> <span class="hljs-attr">handleBackButton</span>=<span class="hljs-string">{backToList}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Step 12: Create the ListTodoLists component</p>
<p>Create a new file src/ListTodoLists.js with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">"./ListTodoLists.css"</span>;
<span class="hljs-keyword">import</span> { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { BiSolidTrash } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/bi"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ListToDoLists</span>(<span class="hljs-params">{
  listSummaries,
  handleSelectList,
  handleNewToDoList,
  handleDeleteToDoList,
}</span>) </span>{
  <span class="hljs-keyword">const</span> labelRef = useRef();

  <span class="hljs-keyword">if</span> (listSummaries === <span class="hljs-literal">null</span>) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"ListToDoLists loading"</span>&gt;</span>Loading to-do lists ...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (listSummaries.length === <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"ListToDoLists"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"box"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          New To-Do List:<span class="hljs-symbol">&amp;nbsp;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{labelRef}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
            handleNewToDoList(document.getElementById(labelRef).value)
          }
        &gt;
          New
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>There are no to-do lists!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  }
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"ListToDoLists"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>All To-Do Lists<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"box"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          New To-Do List:<span class="hljs-symbol">&amp;nbsp;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{labelRef}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
            handleNewToDoList(document.getElementById(labelRef).value)
          }
        &gt;
          New
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {listSummaries.map((summary) =&gt; {
        return (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{summary.id}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"summary"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelectList(summary.id)}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"name"</span>&gt;</span>{summary.name} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"count"</span>&gt;</span>({summary.item_count} items)<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"trash"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(evt)</span> =&gt;</span> {
                evt.stopPropagation();
                handleDeleteToDoList(summary.id);
              }}
            &gt;
              <span class="hljs-tag">&lt;<span class="hljs-name">BiSolidTrash</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        );
      })}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ListToDoLists;
</code></pre>
<p>Create a new file src/ListTodoLists.css with the following content:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.ListToDoLists</span> <span class="hljs-selector-class">.summary</span> {
    <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid lightgray;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">display</span>: flex;
}

<span class="hljs-selector-class">.ListToDoLists</span> <span class="hljs-selector-class">.count</span> {
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">1ex</span>;
    <span class="hljs-attribute">color</span>: blueviolet;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">92%</span>;
}
</code></pre>
<p>Step 13: Create the ToDoList component</p>
<p>Create a new file src/ToDoList.js with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">"./ToDoList.css"</span>;
<span class="hljs-keyword">import</span> { useEffect, useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { BiSolidTrash } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/bi"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ToDoList</span>(<span class="hljs-params">{ listId, handleBackButton }</span>) </span>{
  <span class="hljs-keyword">let</span> labelRef = useRef();
  <span class="hljs-keyword">const</span> [listData, setListData] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">`/api/lists/<span class="hljs-subst">${listId}</span>`</span>);
      <span class="hljs-keyword">const</span> newData = <span class="hljs-keyword">await</span> response.data;
      setListData(newData);
    };
    fetchData();
  }, [listId]);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleCreateItem</span>(<span class="hljs-params">label</span>) </span>{
    <span class="hljs-keyword">const</span> updateData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">`/api/lists/<span class="hljs-subst">${listData.id}</span>/items/`</span>, {
        <span class="hljs-attr">label</span>: label,
      });
      setListData(<span class="hljs-keyword">await</span> response.data);
    };
    updateData();
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleDeleteItem</span>(<span class="hljs-params">id</span>) </span>{
    <span class="hljs-keyword">const</span> updateData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.delete(
        <span class="hljs-string">`/api/lists/<span class="hljs-subst">${listData.id}</span>/items/<span class="hljs-subst">${id}</span>`</span>
      );
      setListData(<span class="hljs-keyword">await</span> response.data);
    };
    updateData();
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleCheckToggle</span>(<span class="hljs-params">itemId, newState</span>) </span>{
    <span class="hljs-keyword">const</span> updateData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.patch(
        <span class="hljs-string">`/api/lists/<span class="hljs-subst">${listData.id}</span>/checked_state`</span>,
        {
          <span class="hljs-attr">item_id</span>: itemId,
          <span class="hljs-attr">checked_state</span>: newState,
        }
      );
      setListData(<span class="hljs-keyword">await</span> response.data);
    };
    updateData();
  }

  <span class="hljs-keyword">if</span> (listData === <span class="hljs-literal">null</span>) {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"ToDoList loading"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"back"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleBackButton}</span>&gt;</span>
          Back
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        Loading to-do list ...
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  }
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"ToDoList"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"back"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleBackButton}</span>&gt;</span>
        Back
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>List: {listData.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"box"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
          New Item:<span class="hljs-symbol">&amp;nbsp;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{labelRef}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
            handleCreateItem(document.getElementById(labelRef).value)
          }
        &gt;
          New
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {listData.items.length &gt; 0 ? (
        listData.items.map((item) =&gt; {
          return (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
              <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">{item.checked</span> ? "<span class="hljs-attr">item</span> <span class="hljs-attr">checked</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">item</span>"}
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleCheckToggle(item.id, !item.checked)}
            &gt;
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{item.checked ? "✅" : "⬜️"} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"label"</span>&gt;</span>{item.label} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"trash"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(evt)</span> =&gt;</span> {
                  evt.stopPropagation();
                  handleDeleteItem(item.id);
                }}
              &gt;
                <span class="hljs-tag">&lt;<span class="hljs-name">BiSolidTrash</span> /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          );
        })
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"box"</span>&gt;</span>There are currently no items.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ToDoList;
</code></pre>
<p>Create a new file src/ToDoList.css with the following content:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.ToDoList</span> <span class="hljs-selector-class">.back</span> {
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">float</span>: left;
}

<span class="hljs-selector-class">.ToDoList</span> <span class="hljs-selector-class">.item</span> {
    <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid lightgray;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">display</span>: flex;
}

<span class="hljs-selector-class">.ToDoList</span> <span class="hljs-selector-class">.label</span> {
    <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">1ex</span>;
}

<span class="hljs-selector-class">.ToDoList</span> <span class="hljs-selector-class">.checked</span> <span class="hljs-selector-class">.label</span> {
    <span class="hljs-attribute">text-decoration</span>: line-through;
    <span class="hljs-attribute">color</span>: lightgray;
}
</code></pre>
<p>Step 14: Update the main CSS file</p>
<p>Replace the content of src/index.css with the following:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">html</span>, <span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-family</span>: -apple-system, BlinkMacSystemFont, <span class="hljs-string">'Segoe UI'</span>, <span class="hljs-string">'Roboto'</span>, <span class="hljs-string">'Oxygen'</span>,
    <span class="hljs-string">'Ubuntu'</span>, <span class="hljs-string">'Cantarell'</span>, <span class="hljs-string">'Fira Sans'</span>, <span class="hljs-string">'Droid Sans'</span>, <span class="hljs-string">'Helvetica Neue'</span>,
    sans-serif;
  <span class="hljs-attribute">-webkit-font-smoothing</span>: antialiased;
  <span class="hljs-attribute">-moz-osx-font-smoothing</span>: grayscale;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">12pt</span>;
}

<span class="hljs-selector-tag">input</span>, <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1em</span>;
}

<span class="hljs-selector-tag">code</span> {
  <span class="hljs-attribute">font-family</span>: source-code-pro, Menlo, Monaco, Consolas, <span class="hljs-string">'Courier New'</span>,
    monospace;
}

<span class="hljs-selector-class">.box</span> {
    <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid lightgray;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1em</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">1em</span>;
}

<span class="hljs-selector-class">.flex</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
}
</code></pre>
<p>This concludes Part 3 of the tutorial, where we set up the React frontend for our FARM stack todo application. We've created the main App component, the ListTodoLists component for displaying all todo lists, and the ToDoList component for individual todo lists. In the next part, we'll focus on running and testing the application.</p>
<h1 id="heading-running-and-testing-the-application">Running and Testing the Application</h1>
<p>Step 18: Run the application using Docker Compose</p>
<ol>
<li><p>Make sure you have Docker and Docker Compose installed on your system</p>
</li>
<li><p>Open a terminal in the root directory of your project (farm-stack-todo)</p>
</li>
<li><p>Build and start the containers:</p>
</li>
</ol>
<pre><code class="lang-python">docker-compose up --build
</code></pre>
<ol start="4">
<li>Once the containers are up and running, open your web browser and go to <a target="_blank" href="http://localhost:8000/">http://localhost:8000</a></li>
</ol>
<p>Step 19: Stopping the application</p>
<ol>
<li><p>If you're running the application without Docker:</p>
<ul>
<li><p>Stop the React development server by pressing Ctrl+C in its terminal</p>
</li>
<li><p>Stop the FastAPI server by pressing Ctrl+C in its terminal</p>
</li>
<li><p>Stop the MongoDB server by pressing Ctrl+C in its terminal</p>
</li>
</ul>
</li>
<li><p>If you're running the application with Docker Compose:</p>
<ul>
<li><p>Press Ctrl+C in the terminal where you ran docker-compose up</p>
</li>
<li><p>Run the following command to stop and remove the containers:</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-python">     docker-compose down
</code></pre>
<p>```</p>
<p>Congratulations! You have successfully built and tested a FARM stack todo application. This application demonstrates the integration of FastAPI, React, and MongoDB in a full-stack web application.</p>
<p>Here are some potential next steps to enhance your application:</p>
<ol>
<li><p>Add user authentication and authorization</p>
</li>
<li><p>Implement data validation and error handling</p>
</li>
<li><p>Add more features like due dates, priorities, or categories for todo items</p>
</li>
<li><p>Improve the UI/UX with a more polished design</p>
</li>
<li><p>Write unit and integration tests for both frontend and backend</p>
</li>
<li><p>Set up continuous integration and deployment (CI/CD) for your application</p>
</li>
</ol>
<p>Remember to keep your dependencies updated and follow best practices for security and performance as you continue to develop your application.</p>
<h1 id="heading-conclusion-and-next-steps">Conclusion and Next Steps</h1>
<p>Congratulations on completing this comprehensive FARM stack tutorial! By building this todo application, you've gained hands-on experience with some of the most powerful and popular technologies in modern web development. You've learned how to create a robust backend API with FastAPI, build a dynamic and responsive frontend with React, persist data with MongoDB, and containerize your entire application using Docker. This project has demonstrated how these technologies work together seamlessly to create a full-featured, scalable web application.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Cleaner Code Using Mongoose Schemas ]]>
                </title>
                <description>
                    <![CDATA[ If you are used to building NodeJS applications using the Mongoose ORM, this article is for you. In it, we'll discuss some cool features of Mongoose schemas that'll help you write more organized and maintainable code. To get the most out of this guid... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-cleaner-code-using-mongoose-schemas/</link>
                <guid isPermaLink="false">66db07581905f28bb66717a2</guid>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ clean code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dry ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ ِAya Nabil Othman ]]>
                </dc:creator>
                <pubDate>Fri, 06 Sep 2024 13:44:56 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725431278897/86823d79-7b9c-4512-a834-edcdd4e11ac3.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you are used to building NodeJS applications using the Mongoose ORM, this article is for you. In it, we'll discuss some cool features of Mongoose schemas that'll help you write more organized and maintainable code.</p>
<p>To get the most out of this guide, you should have a background in JavaScript, understand how Mongoose works, and know Object-Oriented Programming basics.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-a-mongoose-schema">What is a Mongoose Schema?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-discriminator">Discriminator</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-statics">Statics</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-methods">Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-query-builder">Query Builder</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-hooks">Hooks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ol>
<h2 id="heading-what-is-a-mongoose-schema">W<strong>hat is a Mongoose Schema?</strong></h2>
<p>Mongoose schemas provide a structured way to model data in a MongoDB database, allowing you to define the properties and behavior of the documents. Schemas serve as a blueprint for a document that gets saved in the database. They enables developers to enforce data integrity and work with MongoDB in a more intuitive and organized manner.</p>
<p>Within a MongoDB collection, a schema outlines the fields of the documents, their data types, validation rules, default values, constraints, and more.</p>
<p>Programmatically, a Mongoose schema is a JavaScript object. Actually, it is an instance of a built-in class called <code>Schema</code> inside the <code>mongoose</code> module. For this reason, you can add more methods to its prototype. This will help you implement many features as middleware, methods, statics, and more. You will learn about some of them in this tutorial.</p>
<h3 id="heading-features-youll-learn-how-to-implement"><strong>Features you'll learn how to implement:</strong></h3>
<ul>
<li><p><a class="post-section-overview" href="#discriminator">Discriminator</a></p>
</li>
<li><p><a class="post-section-overview" href="#statics">Statics</a></p>
</li>
<li><p><a class="post-section-overview" href="#methods">Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#query-builder">Query Builder</a></p>
</li>
<li><p><a class="post-section-overview" href="#hooks">Hooks</a></p>
</li>
</ul>
<h2 id="heading-discriminator">Discriminator</h2>
<p>A discriminator is a feature that enables you to create multiple models (subtypes) that inherit from a base model (parent). This happens by defining a base schema and then extending it with extra fields specific to each subtype or each child schema.</p>
<p>All documents, regardless of their specific model, are stored in the same MongoDB collection. This keeps your data organized in a single collection while allowing for flexible querying and data management. Also, each document includes a special field that indicates its specific model type, allowing Mongoose to distinguish between the different subtypes.</p>
<p><strong>How to use</strong> <code>discriminator</code><strong>:</strong></p>
<ol>
<li><p>Start by defining a base schema, which will have the common fields among the subtypes. After that, create a model from it.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;

 <span class="hljs-keyword">const</span> baseSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
     <span class="hljs-attr">name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
 }, { <span class="hljs-attr">discriminatorKey</span>: <span class="hljs-string">'kind'</span> }; <span class="hljs-comment">// defaults to '__t');</span>

 <span class="hljs-keyword">const</span> BaseModel = mongoose.model(<span class="hljs-string">'Base'</span>, baseSchema);
</code></pre>
</li>
<li><p>Create the subtypes that extend the base schema by defining the <code>discriminator</code> for each one.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> catSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
     <span class="hljs-attr">meow</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">true</span> }
 });
 <span class="hljs-comment">// subtype</span>
 <span class="hljs-keyword">const</span> Cat = BaseModel.discriminator(<span class="hljs-string">'Cat'</span>, catSchema);

 <span class="hljs-keyword">const</span> dogSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
     <span class="hljs-attr">bark</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">true</span> }
 });
 <span class="hljs-comment">// subtype</span>
 <span class="hljs-keyword">const</span> Dog = BaseModel.discriminator(<span class="hljs-string">'Dog'</span>, dogSchema);
</code></pre>
</li>
<li><p>You can then create documents in the regular way. All the documents will be stored in the same collection, but each has its own type depending on its subtype model.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> fluffy = <span class="hljs-keyword">await</span> Cat.create({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Fluffy'</span> });
 <span class="hljs-keyword">const</span> rover = <span class="hljs-keyword">await</span> Dog.create({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Rover'</span> });
</code></pre>
</li>
</ol>
<h3 id="heading-discriminator-use-case"><code>discriminator</code> use case:</h3>
<p>Let's say that you're building a multi-user Ecommerce web application which accommodates three main user roles: <em>admins</em>, <em>clients</em>, and <em>sellers</em>. Each of these roles plays a crucial part in the ecosystem of online shopping.</p>
<p>If you try to build a class for each role, you'll find that all the three have common fields and methods. You may decide to create a parent schema (user) and some other children schemas (client, seller, admin) that inherit from it.</p>
<p>You can use the <code>discriminator</code> to achieve this.</p>
<p>In your <code>user.model.js</code> file, add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;

<span class="hljs-keyword">const</span> userSchema = mongoose.Schema(
  {
    <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">profilePic</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">birthDate</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">accountAcctivated</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span> },
  },
  {
    <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">discriminatorKey</span>: <span class="hljs-string">"role"</span>,
  }
);

<span class="hljs-keyword">const</span> User = mongoose.model(<span class="hljs-string">"User"</span>, userSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> User;
</code></pre>
<p>Now you have the base model (<code>User</code>) from which other subtypes will inherit. In this parent schema, you define the common fields that all users will share regardless of their roles.</p>
<p>In your <code>client.model.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">"./user.model.js"</span>;

<span class="hljs-keyword">const</span> clientSchema = mongoose.Schema(
  {
    <span class="hljs-attr">products</span>: <span class="hljs-built_in">Array</span>,
    <span class="hljs-attr">address</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">phone</span>: <span class="hljs-built_in">String</span>,
  }
);

<span class="hljs-keyword">const</span> Client = User.discriminator(<span class="hljs-string">"Client"</span>, clientSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Client;
</code></pre>
<p>In your <code>seller.model.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">"./user.model.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> sellerSchema = mongoose.Schema(
  {
    <span class="hljs-attr">rating</span>: <span class="hljs-built_in">Number</span>,
    <span class="hljs-attr">businessType</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">enum</span>: [<span class="hljs-string">"individual"</span>, <span class="hljs-string">"corporation"</span>] },
  }
);

<span class="hljs-keyword">const</span> Seller = User.discriminator(<span class="hljs-string">"Seller"</span>, sellerSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Seller;
</code></pre>
<p>In your <code>admin.model.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">"./user.model.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> adminSchema = mongoose.Schema(
  {
    <span class="hljs-attr">permissions</span>: <span class="hljs-built_in">Array</span>,
    <span class="hljs-attr">assignedTasks</span>: <span class="hljs-built_in">Array</span>,
    <span class="hljs-attr">department</span>: <span class="hljs-built_in">String</span>,
  }
);

<span class="hljs-keyword">const</span> Admin = User.discriminator(<span class="hljs-string">"Admin"</span>, adminSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Admin;
</code></pre>
<p>The subtypes or children will be the <code>Client</code>, <code>Seller</code>, and <code>Admin</code>. In each subtype schema, you should add any extra fields or behaviors specific to this subtype only. By creating the child model using the discriminator, the child model will inherit all the fields and methods of its parent model <code>User</code>.  </p>
<p>So the previous code will create a <code>user</code> collection in the database with each document having a <code>role</code> field either Client, or Seller, or Admin. All documents are now sharing the parent (<code>user</code>) fields, and depending on the <code>role</code> of each document, each has another extra field.</p>
<p>Although all the documents will be saved in one single collection, models are fully separated while coding. What does this mean?</p>
<p>For instance, If you need to retrieve all clients from the <code>User</code> collection, you should write <code>Client.find({})</code>. This statement uses the discriminator key to find all documents whose <code>role</code> is <code>Client</code>. This way, any operations or queries that refer to one of the child models will still be written separately from the parent model.</p>
<p><strong>Note:</strong> Before diving into the next sections, just keep in mind that any statics, methods, query builders, or hooks should be defined before creating the model itself (that is, before <code>const User = mongoose.model("User", userSchema);</code>).</p>
<h2 id="heading-statics">Statics</h2>
<p>Statics are useful for defining functions that operate on the model level. They allow you to define reusable functions for operations related to the entire model. They help encapsulate logic that applies to the model rather than individual documents, making your code cleaner, more organized and maintainable</p>
<p>Methods like <code>find</code>, <code>findOne</code>, <code>findById</code> and others all are methods attached to the model. By using the <code>statics</code> property of Mongoose schemas, you will be able to build your own model method.  </p>
<p>Statics are powerful. By using them, you can encapsulate complex queries that you might want to reuse. Also, you can create statics for operations that modify or aggregate data, such as counting documents or finding documents based on specific criteria.</p>
<h3 id="heading-statics-use-case"><code>statics</code> use case</h3>
<p>Statics are easy to build. You define a static method on your schema using the <code>statics</code> object.</p>
<p>In your <code>user.model.js</code> file, add these static methods, <code>countUsers</code> and <code>findByEmail</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// model method</span>
userSchema.statics.countUsers = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.countDocuments({});
};

<span class="hljs-comment">// model method</span>
userSchema.statics.findByEmail = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">email</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.findOne({ email });
};
</code></pre>
<p>Inside any static method, <code>this</code> refers to the <strong>model</strong> itself. In this example, <code>this</code> in <code>this.findOne({ email })</code> refers to the <code>User</code> model.</p>
<p>Example usage:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findByEmail(<span class="hljs-string">"foo@bar.com"</span>);
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> client = <span class="hljs-keyword">await</span> Client.findByEmail(<span class="hljs-string">"foo@bar.com"</span>);
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> seller = <span class="hljs-keyword">await</span> Seller.findByEmail(<span class="hljs-string">"foo@bar.com"</span>);
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> admin = <span class="hljs-keyword">await</span> Admin.findByEmail(<span class="hljs-string">"foo@bar.com"</span>);
</code></pre>
<p>When you call the static method on your model, the method gets called and <code>this</code> is replaced by the model you called the statics on. This line performs a query to find a single document in the MongoDB collection where the <code>email</code> field matches the provided <code>email</code> argument.</p>
<h2 id="heading-methods">Methods</h2>
<p>Methods are functions that you can define on a schema and that can be called on instances of documents created from this schema. They help encapsulate logic within the document itself, making your code cleaner and more modular.</p>
<p>By using instance methods, you can easily interact with and manipulate the data associated with specific documents.</p>
<h3 id="heading-methods-use-case"><code>methods</code> use case</h3>
<p>You can define methods on the schema using the <code>methods</code> object.</p>
<p>In your <code>user.model.js</code> file, add a document method through which you can check the password of a user:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// instance or document method</span>
userSchema.methods.getProfile = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> (<span class="hljs-subst">${<span class="hljs-built_in">this</span>.email}</span>)`</span>;
};

<span class="hljs-comment">// instance or document method</span>
userSchema.methods.checkPassword = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">password</span>) </span>{
    <span class="hljs-keyword">return</span> password === <span class="hljs-built_in">this</span>.password ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;
};
</code></pre>
<p>Inside any document method, <code>this</code> refers to the <strong>document</strong> itself. In this example, <code>this</code> in <code>this.password</code> refers to the <code>user</code> document at which the method will get called on. This means that you can access all the fields of this document. This is so valuable because you can retrieve, modify, and check for anything related to this document.</p>
<p>Example usage:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> client = <span class="hljs-keyword">await</span> Client.findById(...)
client.checkPassword(<span class="hljs-string">"12345"</span>)
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> seller = <span class="hljs-keyword">await</span> Seller.findById(...)
seller.checkPassword(<span class="hljs-string">"12345"</span>)
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> admin = <span class="hljs-keyword">await</span> Admin.findById(...)
admin.checkPassword(<span class="hljs-string">"12345"</span>)
</code></pre>
<p>Since methods are instance-level functions, they are called on the documents. <code>await Client.findById(...)</code> will return a document that has all the built-in methods as well as your own predefined methods <code>checkPassword</code> and <code>getProfile</code>. So by calling, for example <code>client.checkPassword("12345")</code>, the <code>this</code> keyword in the <code>checkPassword</code> function definition will get replaced with the <code>client</code> document. This in turn will compare the user password with the password saved earlier in the database.</p>
<h2 id="heading-query-builder">Query Builder</h2>
<p>A query builder in Mongoose is a custom method that you can define on the query object to simplify and encapsulate common query patterns. These query builders allow you to create reusable and readable query logic, making it easier to work with your data.</p>
<p>One of the most valuable usages of query builders is chaining. They can be chained with other query builders that you've built or with standard query methods like find, sort, and so on.</p>
<h3 id="heading-query-builder-use-case">Query builder use case</h3>
<p>You define query builders by adding them to the <code>query</code> property of a Mongoose schema.</p>
<p>In your <code>user.model.js</code> file, add a query helper method that lets you implement pagination.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// query helper</span>
userSchema.query.paginate = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">{ page, limit }</span>) </span>{
    <span class="hljs-comment">// some code</span>
    <span class="hljs-keyword">const</span> skip = limit * (page - <span class="hljs-number">1</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.skip(skip).limit(limit);
};
</code></pre>
<p>To implement pagination, you need two important variables: first, the page number, and second, the number of items you will retrieve per page.</p>
<p>To query the database for a specific count of documents, you will always use the <code>skip</code> and <code>limit</code> built-in query methods in <code>mongoose</code>. <code>skip</code> is used to set a cursor after a certain number of documents, after which the query will get implemented. <code>limit</code> is used to retrieve a specific number of documents.</p>
<p>Inside any query builder method, <code>this</code> refers to the <strong>query</strong> itself. And since query builders are chainable, you can call any of them after each other.</p>
<p>Finally, any query builder method should return a <code>mongoose query object</code>, which is why you must write <code>return this.skip(skip).limit(limit)</code>.</p>
<p>Example usage:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> Client.find().paginate({ <span class="hljs-attr">page</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">limit</span>: <span class="hljs-number">5</span> });
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> Seller.find().paginate({ <span class="hljs-attr">page</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">limit</span>: <span class="hljs-number">5</span> });
<span class="hljs-comment">//or</span>
<span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> Admin.find().paginate({ <span class="hljs-attr">page</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">limit</span>: <span class="hljs-number">5</span> });
</code></pre>
<p>You can then call it on any query, and <code>await Client.find().paginate({ page: 2, limit: 5 })</code> will invoke the <code>paginate</code> function and replace the <code>this</code> keyword with <code>Client.find()</code> using the query builder.</p>
<p>You can implement pagination with certain conditions, but you'll always call <code>skip</code> and <code>limit</code>. By defining the <code>paginate</code> query builder you won't repeat yourself and you'll be able to encapsulate the logic in one single function.</p>
<h2 id="heading-hooks">Hooks</h2>
<p>Hooks (also known as middleware) are functions that are executed at specific points in the lifecycle of a document. They allow you to add custom behavior before or after certain operations, such as saving, updating, or removing documents.</p>
<p>Types of Hooks</p>
<ul>
<li><p>Pre Hooks: Executed before an operation.</p>
</li>
<li><p>Post Hooks: Executed after an operation.</p>
</li>
</ul>
<h3 id="heading-hooks-use-case">Hooks use case</h3>
<p>In your <code>user.model.js</code> file, add a <code>post</code> save middleware through which you can send an email for account activation once the user document is saved in the database.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// post hook</span>
userSchema.post(<span class="hljs-string">"save"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">doc, next</span>) </span>{
  <span class="hljs-comment">// send email logic</span>
  <span class="hljs-comment">// if succeeded</span>
  <span class="hljs-keyword">return</span> next();
  <span class="hljs-comment">// if failed</span>
  <span class="hljs-keyword">return</span> next(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to send email!"</span>));
});
</code></pre>
<p>The callback function will get invoked once you create a user through <code>model.create()</code> or any time you call <code>save()</code> method on the user document.</p>
<p>In this this example, if you need to avoid sending emails on save, you should write a condition to be sure that this <code>save</code> is for a new user only. You can write something like <code>if (doc.createdAt.getTime() === doc.updatedAt.getTime())</code>.</p>
<h3 id="heading-summary"><strong>Summary</strong></h3>
<p>In this overview of Mongoose features, we've explored four key concepts: discriminators, statics, methods, and hooks.</p>
<p><strong>Discriminators</strong> allow you to create multiple models that share a common schema enabling different document types to be stored in a single collection. This facilitates data management and querying.  </p>
<p><strong>Statics</strong> are model-level methods that provide reusable functionality applicable to the entire model. They encapsulate complex queries and data manipulation logic, helping to keep your codebase clean and maintainable.  </p>
<p><strong>Methods</strong> are instance-level functions that operate on individual document instances. They allow for custom behaviors and data manipulations specific to each document, so you can modify the document’s data in a specific way, such as formatting or calculating values based on its fields.  </p>
<p><strong>Hooks</strong> (or middleware) enable you to run functions at specific points in the document lifecycle, such as before or after saving, updating or deleting a document. This is useful for implementing validation, logging, or any other side effects related to database operations.  </p>
<p>Together, these features enhance the versatility and organization of your Mongoose models, making it easier to build robust and maintainable applications with MongoDB.</p>
<p><a target="_blank" href="https://github.com/Ayanabilothman/mongoose-schema-features">Here</a> can will find a repository where you can learn more about Mongoose schemas and use cases.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Get Your MongoDB URL to Connect to Your Node.js Application – A Step-by-Step Guide ]]>
                </title>
                <description>
                    <![CDATA[ In my previous article about building a Node.js application, I didn’t fully explain how to obtain the MongoDB URL, as I wanted to keep the article concise. However, I realized that this information is essential for saving data to MongoDB. In this art... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/get-mongodb-url-to-connect-to-a-nodejs-application/</link>
                <guid isPermaLink="false">66ba7ce339eb4776cdcacc56</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ijeoma Igboagu ]]>
                </dc:creator>
                <pubDate>Mon, 12 Aug 2024 21:21:39 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723497228942/b766b557-8230-4bef-8392-d3f4f020c1f4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-an-event-app-with-node-js/">previous article about building a Node.js application</a>, I didn’t fully explain how to obtain the MongoDB URL, as I wanted to keep the article concise. However, I realized that this information is essential for saving data to MongoDB.</p>
<p>In this article, I will guide you through the process of getting your MongoDB URL so you can connect your application effectively. By the end of this tutorial, you’ll have a clear understanding of how to retrieve your MongoDB URL.</p>
<h2 id="heading-lets-get-started">Let's get started! 🚀</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/drum-roll-3.gif" alt="A drum indicating let's get started" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-1-search-for-mongodb-or-visit-their-website">Step 1:  Search for MongoDB or Visit their Website</h2>
<p>To begin, head to the <a target="_blank" href="https://www.mongodb.com">MongoDB</a> website.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/mongodb-website.png" alt="Mongodb website" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-2-click-on-the-sign-in-button-on-their-website">Step 2: Click on the Sign In button on their website.</h2>
<p>This will redirect you to the MongoDB login page. If you don’t have an account yet, you can create one by selecting the <strong>Sign Up</strong> option instead. Since I already have an account, I will log in to access my MongoDB dashboard.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/sigin-mongodb.gif" alt="Redirection to login or signup page of mongodb" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-3-access-the-dashboard">Step 3: Access the Dashboard</h2>
<p>Once you log in, you'll have access to the dashboard. But first, you need to create a project folder.</p>
<h3 id="heading-why-do-you-need-a-project-folder">Why Do You Need a Project Folder?</h3>
<p>This is for organizational purposes, helping you keep track of which projects you are working on.</p>
<p><strong>To create a project folder</strong></p>
<ul>
<li><p>Click on the <strong>Projects</strong> section at the top, indicated by a folder icon. This will reveal a dropdown menu.</p>
</li>
<li><p>From the dropdown, click on <strong>New Project</strong>. This will redirect you to a page where you can create your new project.</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/use-mongodb.gif" alt="Create a new project" width="600" height="400" loading="lazy"></p>
<ul>
<li>Click the <strong>Next</strong> button to proceed to the project creation page.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/create-project.png" alt="Creating a project continues" width="600" height="400" loading="lazy"></p>
<p>After creating your project, you will be redirected back to your dashboard, where you will see your newly created project folder. You can now start working on this specific project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/project-created-mongodb-1.png" alt="Going back to the dashboard" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-4-creating-a-cluster">Step 4: Creating a Cluster</h2>
<p>To obtain the MongoDB connection URL, it is essential to create a <strong>Cluster</strong>.</p>
<h3 id="heading-what-is-a-cluster">What is a cluster?</h3>
<p>A cluster in MongoDB is a group of servers that work together to store and manage your data, providing high availability and scalability.</p>
<p><strong>To create a cluster:</strong></p>
<ol>
<li><p>On your dashboard, click on the <strong>Clusters</strong> button as shown in the picture of <strong>Step 3</strong> above.</p>
</li>
<li><p>Next, this will direct you to a page called "<strong>Deploy your cluster</strong>" where you get to create your cluster.</p>
</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/cluster-mongoDB.gif" alt="Creating a cluster" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-5-create-a-username-for-your-connection-url">Step 5: Create a Username for Your Connection URL</h2>
<p>After creating a cluster, you will be taken to a page where you need to create a username and password for the connection URL. The password can be autogenerated, or you can create your own.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/creating-a-username-for-mongodb.png" alt="Creating Username and password" width="600" height="400" loading="lazy"></p>
<h3 id="heading-why-do-i-have-to-create-a-username">Why Do I Have to Create a Username?</h3>
<p>Creating a username is essential for managing access to your MongoDB cluster. A username, along with a password, ensures that only authorized users can access your database. This adds a layer of security, protecting your data from unauthorized access.</p>
<h3 id="heading-benefits-of-creating-a-username">Benefits of creating a username:</h3>
<ul>
<li><p><strong>Security:</strong> Ensures that your database is only accessible to those with the correct credentials.</p>
</li>
<li><p><strong>Management:</strong> You can track who is accessing your database and manage permissions.</p>
</li>
<li><p><strong>Accountability:</strong> Helps in auditing and monitoring activities within your database.</p>
</li>
</ul>
<h2 id="heading-step-6-auto-generation-of-the-mongodb-connection-url">Step 6: Auto Generation  of The MongoDB Connection URL</h2>
<p>Once you click the <strong>Create User</strong> button, you will be redirected to a page where your connection URL is automatically generated. Copy this URL and paste it into your <code>.env</code> file to establish a connection to your database. Alternatively, you can paste it directly into your <code>app.js</code> or <code>server.js</code> file, as I <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-an-event-app-with-node-js/">explained in my previous article</a>.</p>
<p>Feel free to let me know if you need assistance!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/getting-the-strringt-fot-conn.png" alt="Automatic generation of the URL" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By following the steps outlined in this article, you should now understand how to obtain your MongoDB connection URL. Remember, creating a username and password for your database access is crucial for ensuring the security and management of your data.</p>
<p>If you encounter any challenges along the way, don't hesitate to refer back to this guide, ask questions or better still consult the official <a target="_blank" href="https://www.mongodb.com/resources/products/fundamentals/basics">MongoDB documentation</a> for further assistance.</p>
<p>If you found this article helpful, share it with others who may also find it interesting.</p>
<p>Stay updated with my projects by following me on <a target="_blank" href="https://https//twitter.com/ijaydimples">Twitter</a>, <a target="_blank" href="https://www.linkedin.com/in/ijeoma-igboagu/">LinkedIn</a> and <a target="_blank" href="https://github.com/ijayhub">GitHub</a>.</p>
<p>Thank you for reading💖.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Using Entity Framework Core with MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ Entity Framework Core is a popular ORM (Object-Relational Mapper) for .NET applications, allowing developers to work with databases using .NET objects. It can be used with many types of databases, including MongoDB. In this article, you will learn ho... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/using-entity-framework-core-with-mongodb/</link>
                <guid isPermaLink="false">66a7ab00c6276b10f061c86e</guid>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Mon, 29 Jul 2024 14:45:20 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721834746254/fb4a9197-8076-48a5-b402-116d8289863c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Entity Framework Core is a popular ORM (Object-Relational Mapper) for .NET applications, allowing developers to work with databases using .NET objects. It can be used with many types of databases, including MongoDB.</p>
<p>In this article, you will learn how you can use Entity Framework Core with MongoDB. This article covers the basics, explains the benefits, and provides a step-by-step tutorial. Whether you're new to MongoDB or Entity Framework Core, or just looking to integrate these tools into your .NET projects, this guide will help you bridge the gap between relational and NoSQL databases.</p>
<p>The article starts with a brief introduction to MongoDB as well as an introduction to Microsoft's Entity Framework Core. Then, it covers how to use the MongoDB EF Core Provider. After going though technical details with some basic examples, you will create a full project with MongoB and Entity Framework Core so you can see how everything works together. The project will use MongoDB Atlas sample data to create a Restaurant reservation system.</p>
<p>There is also a video version of this article that you can <a target="_blank" href="https://youtu.be/fv2-A5e-KHA">watch on the freeCodeCamp.org YouTube channel</a>.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/fv2-A5e-KHA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h1 id="heading-intro-to-mongodb">Intro to MongoDB</h1>
<p>MongoDB is a popular NoSQL database designed to handle large volumes of data and provide high performance, scalability, and flexibility. Unlike traditional relational databases, MongoDB stores data in flexible, JSON-like documents. This document-oriented approach allows for the storage of complex data structures in a more natural and intuitive way.</p>
<p>In MongoDB, data is stored in collections, which are similar to tables in relational databases but without a fixed schema. This means you can have documents with different structures in the same collection. This flexibility is one of the key advantages of using MongoDB, especially when dealing with unstructured or semi-structured data.</p>
<p>Let's take a look at an example of a MongoDB document. Imagine we have a collection called <code>users</code> that stores information about users in an application. Here is what a typical document might look like:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"_id"</span>: <span class="hljs-string">"12345"</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>,
    <span class="hljs-attr">"email"</span>: <span class="hljs-string">"johndoe@example.com"</span>,
    <span class="hljs-attr">"age"</span>: <span class="hljs-number">30</span>,
    <span class="hljs-attr">"address"</span>: {
        <span class="hljs-attr">"street"</span>: <span class="hljs-string">"123 Main St"</span>,
        <span class="hljs-attr">"city"</span>: <span class="hljs-string">"Anytown"</span>,
        <span class="hljs-attr">"state"</span>: <span class="hljs-string">"CA"</span>,
        <span class="hljs-attr">"zip"</span>: <span class="hljs-string">"12345"</span>
    },
    <span class="hljs-attr">"hobbies"</span>: [<span class="hljs-string">"reading"</span>, <span class="hljs-string">"travelling"</span>, <span class="hljs-string">"coding"</span>]
}
</code></pre>
<p>In this document, we have various fields such as <code>name</code>, <code>email</code>, <code>age</code>, and <code>address</code>. The <code>address</code> field itself is an embedded document containing multiple sub-fields like <code>street</code>, <code>city</code>, <code>state</code>, and <code>zip</code>. Additionally, the <code>hobbies</code> field is an array of strings.</p>
<p>While this looks like JSON, MongoDB stores data in a binary format called BSON (Binary JSON). BSON extends the JSON model to provide additional data types, such as integers, floats, dates, and binary data. This binary format is optimized for performance and flexibility, allowing MongoDB to efficiently store and retrieve data.</p>
<p>Another important feature of MongoDB is its ability to scale horizontally. This means you can distribute your data across multiple servers, making it easier to manage large datasets and ensure high availability. MongoDB also supports rich queries, indexing, and aggregation, making it a powerful tool for a wide range of applications.</p>
<p>For example, you can perform a query to find all users who live in a specific city:</p>
<pre><code class="lang-json">db.users.find({ <span class="hljs-attr">"address.city"</span>: <span class="hljs-string">"Anytown"</span> })
</code></pre>
<p>Or you can find users who have a specific hobby:</p>
<pre><code class="lang-json">db.users.find({ <span class="hljs-attr">"hobbies"</span>: <span class="hljs-string">"coding"</span> })
</code></pre>
<p>MongoDB is widely used in various industries, from e-commerce and content management to real-time analytics and Internet of Things (IoT) applications. Its flexibility and scalability make it an excellent choice for modern applications that need to handle diverse and dynamic data.</p>
<p>Now that we have a basic understanding of what MongoDB is and why it's popular, let's move on to another essential tool in our tech stack: Microsoft's Entity Framework Core.</p>
<h1 id="heading-intro-to-microsofts-entity-framework-core">Intro to Microsoft's Entity Framework Core</h1>
<p>Entity Framework Core, often abbreviated as EF Core, is a modern object-database mapper for .NET. It allows developers to work with a database using .NET objects, eliminating the need for most of the data-access code that developers usually need to write.</p>
<p>EF Core is a lightweight, extensible, and cross-platform version of the popular Entity Framework (EF) data access technology. It supports a variety of database engines, including SQL Server, SQLite, and MongoDB.</p>
<p>One of the main benefits of using EF Core is that it enables developers to work with data in a more intuitive and object-oriented way. Instead of writing raw SQL queries, you can interact with your database using LINQ (Language Integrated Query) and strongly-typed classes.</p>
<p>Let's take a look at a basic example. Imagine we have a <code>Product</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Product</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> ProductId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> Price { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<p>This is pretty simple with just three fields. Using EF Core, you can create a context class that represents a session with the database and includes a <code>DbSet</code> for each entity type you want to query or save:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AppDbContext</span> : <span class="hljs-title">DbContext</span>
{
    <span class="hljs-keyword">public</span> DbSet&lt;Product&gt; Products { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnConfiguring</span>(<span class="hljs-params">DbContextOptionsBuilder optionsBuilder</span>)</span>   
    {
        optionsBuilder.Use&lt;Your_SQL_Database_function&gt;(<span class="hljs-string">"YourConnectionStringHere"</span>);
    }
}
</code></pre>
<p>This code defines a class named <code>AppDbContext</code> that inherits from Entity Framework Core's <code>DbContext</code> class. This class is used to interact with the database. Inside this class, there is a <code>DbSet&lt;Product&gt;</code> property called <code>Products</code>, which represents a collection of <code>Product</code> entities and corresponds to a table named <code>Products</code> in the database. The <code>OnConfiguring</code> method is overridden to configure the database connection, you can specify various databases as the database provider. The method uses an <code>optionsBuilder</code> to set up the connection with a placeholder for the actual database connection string. This connection string obviously should be replaced with the real one containing the necessary details to connect to the database. When you create an instance of <code>AppDbContext</code> in the application, it uses this configuration to perform operations like querying or saving <code>Product</code> entities in the <code>Products</code> table.</p>
<p>With this setup, you can perform CRUD (Create, Read, Update, Delete) operations using EF Core. For example, to add a new product to the database, you can use this code.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> AppDbContext())
{
    <span class="hljs-keyword">var</span> product = <span class="hljs-keyword">new</span> Product { Name = <span class="hljs-string">"Laptop"</span>, Price = <span class="hljs-number">999.99</span>M };
    context.Products.Add(product);
    context.SaveChanges();
}
</code></pre>
<p>This code demonstrates how to add a new product to the database using Entity Framework Core. An instance of <code>AppDbContext</code> is created, and within this context, a new <code>Product</code> object with the name "Laptop" and price 999.99 is instantiated. This new product is then added to the <code>Products</code> collection managed by the <code>AppDbContext</code>. Finally, the <code>SaveChanges</code> method is called to save the changes to the database, effectively inserting the new product into the <code>Products</code> table.</p>
<p>To query products, you can use LINQ:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> AppDbContext())
{
    <span class="hljs-keyword">var</span> products = context.Products.Where(p =&gt; p.Price &gt; <span class="hljs-number">500</span>).ToList();
    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> product <span class="hljs-keyword">in</span> products)
    {
        Console.WriteLine(<span class="hljs-string">$"Product: <span class="hljs-subst">{product.Name}</span>, Price: <span class="hljs-subst">{product.Price}</span>"</span>);  
    }
}
</code></pre>
<p>This code demonstrates how to query the database using Entity Framework Core. An instance of <code>AppDbContext</code> is created, and within this context, a query is made to retrieve all products with a price greater than 500. The results are stored in a list called <code>products</code>. Then, a loop iterates through each product in the list, printing the name and price of each product to the console.</p>
<p>EF Core takes care of translating these LINQ queries into the appropriate SQL commands for your database, making data access simpler and more maintainable.</p>
<p>EF Core also supports advanced features like change tracking, lazy loading, and migrations, which help you manage database schema changes over time.</p>
<p>In summary, EF Core is a powerful ORM that simplifies data access in .NET applications by allowing you to work with your data using .NET objects and LINQ. Its support for multiple database engines and its extensibility make it a versatile choice for a wide range of applications.</p>
<p>Next, we'll see how the MongoDB EF Core Provider bridges the gap between MongoDB and EF Core, allowing us to use the familiar EF Core patterns with a MongoDB database.</p>
<h1 id="heading-how-the-mongodb-ef-core-provider-bridges-the-gap">How the MongoDB EF Core Provider Bridges the Gap</h1>
<p>The MongoDB Entity Framework Core Provider is a tool that enables developers to use MongoDB with Entity Framework Core (EF Core), combining the flexibility of MongoDB with the familiar API and design patterns of EF Core. This provider allows you to work with MongoDB using the same code-first and LINQ query methodologies that you would use with relational databases, streamlining development and reducing the learning curve for those already familiar with EF Core.</p>
<p>The MongoDB EF Core Provider bridges the gap between MongoDB and EF Core by supporting basic CRUD operations, LINQ queries, and embedded documents, among other features. Here are some key capabilities:</p>
<ol>
<li><p><strong>Code-First Workflows</strong>: You can define your data models in C# and use EF Core to generate the MongoDB schema, rather than starting with the database schema and generating code from it. This is particularly useful for developers who prefer to manage their database structure through code.</p>
</li>
<li><p><strong>CRUD Operations</strong>: The provider supports basic create, read, update, and delete operations. For example, you can add a new record to the database using the same code we saw earlier:</p>
<pre><code class="lang-csharp"> <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> AppDbContext())
 {
     <span class="hljs-keyword">var</span> product = <span class="hljs-keyword">new</span> Product { Name = <span class="hljs-string">"Laptop"</span>, Price = <span class="hljs-number">999.99</span>M };
     context.Products.Add(product);
     context.SaveChanges();
 }
</code></pre>
</li>
<li><p><strong>LINQ Query Support</strong>: You can use LINQ to perform queries against MongoDB, allowing you to leverage your existing knowledge of C# and .NET to interact with the database.</p>
<pre><code class="lang-csharp"> <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> AppDbContext())
 {
     <span class="hljs-keyword">var</span> products = context.Products.Where(p =&gt; p.Price &gt; <span class="hljs-number">500</span>).ToList();
     <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> product <span class="hljs-keyword">in</span> products)
     {
         Console.WriteLine(<span class="hljs-string">$"Product: <span class="hljs-subst">{product.Name}</span>, Price: <span class="hljs-subst">{product.Price}</span>"</span>);
     }
 }
</code></pre>
</li>
<li><p><strong>Change Tracking</strong>: EF Core’s change tracking capabilities are supported, enabling automatic detection and saving of changes made to your data entities.</p>
</li>
<li><p><strong>Embedded Documents</strong>: The provider supports embedded documents, allowing you to store related data within a single document, which is a common pattern in MongoDB.</p>
</li>
<li><p><strong>Class Mapping and Serialization</strong>: Your C# classes are mapped to MongoDB collections, with support for various data types and serialization settings to ensure that data is stored correctly.</p>
</li>
</ol>
<h1 id="heading-data-modeling-and-crud-operations-using-mongodb-atlas">Data Modeling and CRUD Operations Using MongoDB Atlas</h1>
<p>Now we'll go over a quick example on how to use the MongoDB EF Core Provider. But soon, we'll create a full project in Visual Studio Code so you can see everything in context.</p>
<p>In this section, we will explore how to define data models and perform CRUD (Create, Read, Update, Delete) operations using the MongoDB Entity Framework Core (EF) Provider with MongoDB Atlas. This integration allows you to leverage the flexibility of MongoDB with the familiar patterns of EF Core.</p>
<h4 id="heading-setting-up-your-environment">Setting Up Your Environment</h4>
<p>To get started, you need to add the necessary NuGet packages to your project:</p>
<pre><code class="lang-bash">dotnet add package MongoDB.EntityFrameworkCore
</code></pre>
<p>The MS EF Core Package and the MongoDB C# Driver are added as a dependency when you add the MongoDB EF Core provider package. These packages allow your application to interact with MongoDB through EF Core, using the same context and entity definitions you would use with a relational database.</p>
<h4 id="heading-setting-up-mongodb-atlas">Setting Up MongoDB Atlas</h4>
<p>Before you can perform CRUD operations, you need to set up a MongoDB Atlas cluster and connect your application to it.</p>
<p>Here are the steps. Note that we'll be going over these in detail when we create the project soon.</p>
<ol>
<li><p><strong>Create a MongoDB Atlas Account</strong>: Sign up for a free account at <a target="_blank" href="https://www.mongodb.com/cloud/atlas/register?utm_campaign=freecodecamp_ef&amp;utm_source=freecodecamp&amp;utm_medium=referral">MongoDB Atlas</a>.</p>
</li>
<li><p><strong>Create a Cluster</strong>: Set up a new cluster. MongoDB Atlas provides a free tier that is perfect for development and small-scale applications.</p>
</li>
<li><p><strong>Get Connection String</strong>: Obtain your connection string from the MongoDB Atlas dashboard. It will look something like this:</p>
<pre><code class="lang-plaintext"> mongodb+srv://&lt;username&gt;:&lt;password&gt;@cluster0.mongodb.net/myFirstDatabase?retryWrites=true&amp;w=majority
</code></pre>
</li>
</ol>
<h4 id="heading-defining-the-data-model">Defining the Data Model</h4>
<p>Define a class to use as a model for your entity. For this example, we'll create a <code>Customer</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span>
{
    <span class="hljs-keyword">public</span> ObjectId Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> String Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> String Order { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<p>This <code>Customer</code> class represents the structure of the documents stored in the MongoDB collection.</p>
<h4 id="heading-create-a-db-context-class">Create a DB Context Class</h4>
<p>To begin using Entity Framework Core, create a context class that derives from DBContext. The<code>DbContext</code> derived class instance represents a database session and is used to query and save instances of your entities.</p>
<p>The <code>DBContext</code> class exposes <code>DBSet</code> properties that specify the entities you can interact with while using that context.</p>
<p>This example creates an instance of a <code>DBContext</code> derived class and specifies the <code>Customer</code> object as a <code>DBSet</code> property:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MyDbContext</span> : <span class="hljs-title">DbContext</span>
{
    <span class="hljs-keyword">public</span> DbSet&lt;Customer&gt; Customers { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyDbContext</span>(<span class="hljs-params">DbContextOptions options</span>)
        : <span class="hljs-title">base</span>(<span class="hljs-params">options</span>)</span>
    {
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnModelCreating</span>(<span class="hljs-params">ModelBuilder modelBuilder</span>)</span>
    {
        <span class="hljs-keyword">base</span>.OnModelCreating(modelBuilder);
        modelBuilder.Entity&lt;Customer&gt;().ToCollection(<span class="hljs-string">"customers"</span>);
    }
}
</code></pre>
<h4 id="heading-code-first-workflow">Code-First Workflow</h4>
<p>With the MongoDB EF Provider, you can use a code-first workflow. This means you define your classes first, and EF Core will handle the creation and management of the underlying MongoDB schema. This is particularly useful for MongoDB, which does not enforce a schema, allowing for flexible and dynamic data structures.</p>
<p><strong>Use MongoDB</strong></p>
<p>Once we've created a <code>DBContext</code> class, we need to construct a <code>DbContextOptionsBuilder</code> object and call its <code>UseMongoDB()</code> method. This method takes two parameters: a <code>MongoClient</code> instance and the name of the database that stores the collections you are working with.</p>
<p>The <code>UseMongoDB()</code> method returns a <code>DbContextOptions</code> object. Pass the <code>Options</code> property of this object to the constructor for your <code>DBContext</code> class.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> mongoClient = <span class="hljs-keyword">new</span> MongoClient(<span class="hljs-string">"&lt;Your MongoDB Connection URI&gt;"</span>);

<span class="hljs-keyword">var</span> dbContextOptions =
    <span class="hljs-keyword">new</span> DbContextOptionsBuilder&lt;MyDbContext&gt;().UseMongoDB(mongoClient, <span class="hljs-string">"&lt;Database Name"</span>);  

<span class="hljs-keyword">var</span> db = <span class="hljs-keyword">new</span> MyDbContext(dbContextOptions.Options);
</code></pre>
<h3 id="heading-crud-operations">CRUD Operations</h3>
<p>Now let's see how to code the CRUD operations. We'll just focus on each operation individually.</p>
<h4 id="heading-create-operation">Create Operation</h4>
<p>To create a new document in MongoDB, you use the <code>Add</code> method on the <code>DbSet</code> and call <code>SaveChanges</code>. This is an example of creating a new customer:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> MyDbContext(options))
{
    <span class="hljs-keyword">var</span> customer = <span class="hljs-keyword">new</span> Customer { Name = <span class="hljs-string">"Beau Carnes"</span>, Order = <span class="hljs-string">"Laptop"</span> };
    context.Customers.Add(customer);
    context.SaveChanges();
}
</code></pre>
<p>This code creates a new <code>Customer</code> instance and adds it to the <code>Customers</code> collection. The <code>SaveChanges</code> method saves the new customer to the MongoDB database.</p>
<h4 id="heading-read-operation">Read Operation</h4>
<p>To read documents from the MongoDB collection, you can use LINQ queries on the <code>DbSet</code>. This is an example of retrieving all customers:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> MyDbContext(options))
{
    <span class="hljs-keyword">var</span> customers = context.Customers.ToList();
    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> customer <span class="hljs-keyword">in</span> customers)
    {
        Console.WriteLine(<span class="hljs-string">$"Customer: <span class="hljs-subst">{customer.Name}</span>, Order: <span class="hljs-subst">{customer.Order}</span>"</span>); 
    }
}
</code></pre>
<p>This code retrieves all customers from the <code>Customers</code> collection and prints their details.</p>
<h4 id="heading-update-operation">Update Operation</h4>
<p>To update an existing document, you retrieve the document, modify its properties, and call <code>SaveChanges</code>. This is an example of updating a customer's order:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> MyDbContext(options))
{
    <span class="hljs-keyword">var</span> customer = context.Customers.FirstOrDefault(c =&gt; c.Name == <span class="hljs-string">"Beau Carnes"</span>); 
    <span class="hljs-keyword">if</span> (customer != <span class="hljs-literal">null</span>)
    {
        customer.Order = <span class="hljs-string">"Smartphone"</span>;
        context.SaveChanges();
    }
}
</code></pre>
<p>This code finds the customer named "Beau Carnes" and updates their order to "Smartphone".</p>
<h4 id="heading-delete-operation">Delete Operation</h4>
<p>To delete a document, you retrieve the document, remove it from the <code>DbSet</code>, and call <code>SaveChanges</code>. This is an example of deleting a customer:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> context = <span class="hljs-keyword">new</span> MyDbContext(options))
{
    <span class="hljs-keyword">var</span> customer = context.Customers.FirstOrDefault(c =&gt; c.Name == <span class="hljs-string">"Beau Carnes"</span>); 
    <span class="hljs-keyword">if</span> (customer != <span class="hljs-literal">null</span>)
    {
        context.Customers.Remove(customer);
        context.SaveChanges();
    }
}
</code></pre>
<p>This code finds the customer named "Beau Carnes" and deletes them from the <code>Customers</code> collection.</p>
<h4 id="heading-change-tracking">Change Tracking</h4>
<p>EF Core's change tracking capabilities are fully supported, enabling efficient updates to documents. When you modify an entity and call <code>SaveChanges</code>, EF Core will generate the necessary MongoDB commands to update only the changed fields.</p>
<p>By using the MongoDB EF Provider, you can seamlessly integrate MongoDB's flexible document model with EF Core's robust ORM capabilities, providing a powerful toolset for .NET developers to build modern applications.</p>
<h1 id="heading-tutorial">Tutorial</h1>
<p>Now let's put everything together and create a restaurant reservation system.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>In order to follow along with this tutorial, you are going to need a few things:</p>
<ul>
<li><p>.NET 7.0.</p>
</li>
<li><p>Basic knowledge of ASP.NET MVC and C#.</p>
</li>
<li><p>Free <a target="_blank" href="https://www.mongodb.com/try"><strong>MongoDB Atlas account and free tier cluster</strong>.</a></p>
</li>
</ul>
<h2 id="heading-create-the-project">Create the project</h2>
<p>ASP.NET Core is a very flexible web framework, allowing you to scaffold out different types of web applications that have slight differences in terms of their UI or structure. For this tutorial, we are going to create an MVC project that will make use of static files and controllers. There are other types of front end you could use, such as React, but MVC with .cshtml views is the most commonly used. To create the project, we are going to use the .NET CLI:</p>
<pre><code class="lang-plaintext">dotnet new mvc -o RestRes
</code></pre>
<p>Because we used the CLI, although easier, it only creates the csproj file and not the solution file which allows us to open it in Visual Studio, so we will fix that.</p>
<pre><code class="lang-plaintext">cd RestRes
dotnet new sln
dotnet sln .\RestRes.sln add .\RestRes.csproj
</code></pre>
<h2 id="heading-add-the-nuget-packages">Add the NuGet packages</h2>
<p>Now that we have the new project created, we will want to go ahead and add the required NuGet packages. Either using the NuGet Package Manager or using the .NET CLI command below, add the MongoDB MongoDB.EntityFrameworkCore package.</p>
<pre><code class="lang-plaintext">dotnet add package MongoDB.EntityFrameworkCore
</code></pre>
<h2 id="heading-create-the-models">Create the models</h2>
<p>Before we can start implementing the new packages we just added, we need to create the models that represent the entities we want in our restaurant reservation system that will of course be stored in MongoDB Atlas as documents. In the following subsections, we will create the following models:</p>
<ul>
<li><p>Restaurant</p>
</li>
<li><p>Reservation</p>
</li>
<li><p>MongoDBSettings</p>
</li>
</ul>
<h3 id="heading-restaurant">Restaurant</h3>
<p>First, we need to create our restaurant model that will represent the restaurants that are available to be reserved in our system.</p>
<ol>
<li><p>Create a new file in the Models folder called Restaurant.cs.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> MongoDB.Bson;
<span class="hljs-keyword">using</span> MongoDB.EntityFrameworkCore;
<span class="hljs-keyword">using</span> System.ComponentModel.DataAnnotations;


<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Models</span>
{
    [<span class="hljs-meta">Collection(<span class="hljs-meta-string">"restaurants"</span>)</span>]    
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Restaurant</span>
    {

        <span class="hljs-keyword">public</span> ObjectId Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-meta-string">"You must provide a name"</span>)</span>]
        [<span class="hljs-meta">Display(Name = <span class="hljs-meta-string">"Name"</span>)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span>? name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }


        [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-meta-string">"You must add a cuisine type"</span>)</span>]
        [<span class="hljs-meta">Display(Name = <span class="hljs-meta-string">"Cuisine"</span>)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span>? cuisine { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }


        [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-meta-string">"You must add the borough of the restaurant"</span>)</span>]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span>? borough { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    }
}
</code></pre>
<p>The collection attribute before the class tells the application what collection inside the database we are using. This allows us to have differing names or capitalization between our class and our collection should we want to.</p>
<h3 id="heading-reservation">Reservation</h3>
<p>We also need to create a reservation class to represent any reservations we take in our system.</p>
<ol>
<li><p>Create a new file inside the Models folder called Reservation.cs.</p>
</li>
<li><p>Add the following code to it:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> MongoDB.Bson;
<span class="hljs-keyword">using</span> MongoDB.EntityFrameworkCore;
<span class="hljs-keyword">using</span> System.ComponentModel.DataAnnotations;


<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Models</span>
{
    [<span class="hljs-meta">Collection(<span class="hljs-meta-string">"reservations"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Reservation</span>
    {
        <span class="hljs-keyword">public</span> ObjectId Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }


        <span class="hljs-keyword">public</span> ObjectId RestaurantId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }


        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span>? RestaurantName { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

        [<span class="hljs-meta">Required(ErrorMessage = <span class="hljs-meta-string">"The date and time is required to make this reservation"</span>)</span>]
        [<span class="hljs-meta">Display(Name = <span class="hljs-meta-string">"Date"</span>)</span>]
        <span class="hljs-keyword">public</span> DateTime date { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    }
}
</code></pre>
<h3 id="heading-mongodbsettings">MongoDBSettings</h3>
<p>Although it won’t be a document in our database, we need a model class to store our MongoDB-related settings so they can be used across the application.</p>
<ol>
<li><p>Create another file in Models called MongoDBSettings.cs.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Models</span>
{
  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MongoDBSettings</span>
  {
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> AtlasURI { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> DatabaseName { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
  }
}
</code></pre>
<h2 id="heading-setting-up-ef-core">Setting up EF Core</h2>
<p>This is the exciting part. We are going to start to implement EF Core and take advantage of the new MongoDB Provider. If you are used to working with EF Core already, some of this will be familiar to you.</p>
<h3 id="heading-restaurantreservationdbcontext">RestaurantReservationDbContext</h3>
<ol>
<li><p>Create a Services folder, and the create a file called RestaurantReservationDbContext.cs.</p>
</li>
<li><p>Replace the code inside the namespace with the following:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">RestaurantReservationDbContext</span> : <span class="hljs-title">DbContext</span>
    {
        <span class="hljs-keyword">public</span> DbSet&lt;Restaurant&gt; Restaurants { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }      


        <span class="hljs-keyword">public</span> DbSet&lt;Reservation&gt; Reservations { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }


        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">RestaurantReservationDbContext</span>(<span class="hljs-params">DbContextOptions options</span>)
        : <span class="hljs-title">base</span>(<span class="hljs-params">options</span>)</span>
        {
        }


        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OnModelCreating</span>(<span class="hljs-params">ModelBuilder modelBuilder</span>)</span>
        {
            <span class="hljs-keyword">base</span>.OnModelCreating(modelBuilder);


            modelBuilder.Entity&lt;Restaurant&gt;();
            modelBuilder.Entity&lt;Reservation&gt;();
        }
    }
}
</code></pre>
<p>If you are used to EF Core, this will look familiar. The class extends the DbContext and we create DbSet properties that store the models that will also be present in the database. We also override the OnModelCreating method. You may notice that unlike when using SQL Server, we don’t call .ToTable(). We could call ToCollection instead but this isn’t required here as we specify the collection using attributes on the classes.</p>
<h3 id="heading-add-connection-string-and-database-details-to-appsettings">Add connection string and database details to appsettings</h3>
<p>Earlier, we created a MongoDBSettings model, and now we need to add the values that the properties map to into our appsettings.</p>
<ol>
<li><p>In both appsettings.json and appsettings.Development.json, add the following new section:</p>
<pre><code class="lang-csharp">  <span class="hljs-string">"MongoDBSettings"</span>: {
    <span class="hljs-string">"AtlasURI"</span>: <span class="hljs-string">"mongodb+srv://&lt;username&gt;:&lt;password&gt;@&lt;url&gt;"</span>,
    <span class="hljs-string">"DatabaseName"</span>: <span class="hljs-string">"restaurants"</span>
  }
</code></pre>
</li>
<li><p>Replace the Atlas URI with your own connection string from Atlas.</p>
</li>
</ol>
<h3 id="heading-updating-programcs">Updating program.cs</h3>
<p>Now we have configured our models and DbContext, it is time to add them to our program.cs file.</p>
<p>After the existing line <a target="_blank" href="http://builder.Services"><code>builder.Services</code></a><code>.AddControllersWithViews();</code>, add the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> mongoDBSettings = builder.Configuration.GetSection(<span class="hljs-string">"MongoDBSettings"</span>).Get&lt;MongoDBSettings&gt;();
builder.Services.Configure&lt;MongoDBSettings&gt;(builder.Configuration.GetSection(<span class="hljs-string">"MongoDBSettings"</span>));

builder.Services.AddDbContext&lt;RestaurantReservationDbContext&gt;(options =&gt;
options.UseMongoDB(mongoDBSettings.AtlasURI ?? <span class="hljs-string">""</span>, mongoDBSettings.DatabaseName ?? <span class="hljs-string">""</span>));
</code></pre>
<h2 id="heading-creating-the-services">Creating the services</h2>
<p>Now, it is time to add the services we will use to talk to the database via the RestaurantBookingDbContext we created. For each service, we will create an interface and the class that implements it.</p>
<h3 id="heading-irestaurantservice-and-restaurantservice">IRestaurantService and RestaurantService</h3>
<p>The first interface and service we will implement is for carrying out the CRUD operations on the restaurants collection. This is known as the repository pattern. You may see people interact with the DbContext directly. But most people use this pattern, which is why we are including it here.</p>
<ol>
<li><p>If you haven’t already, create a Services folder to store our new classes.</p>
</li>
<li><p>Create an IRestaurantService interface and add the following code for the methods we will implement:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> MongoDB.Bson;
<span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IRestaurantService</span>
    {
        <span class="hljs-function">IEnumerable&lt;Restaurant&gt; <span class="hljs-title">GetAllRestaurants</span>(<span class="hljs-params"></span>)</span>;
        Restaurant? GetRestaurantById(ObjectId id);

        <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">AddRestaurant</span>(<span class="hljs-params">Restaurant newRestaurant</span>)</span>;

        <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">EditRestaurant</span>(<span class="hljs-params">Restaurant updatedRestaurant</span>)</span>;

        <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">DeleteRestaurant</span>(<span class="hljs-params">Restaurant restaurantToDelete</span>)</span>;
    }
}
</code></pre>
<ol>
<li><p>Create a RestaurantService class file.</p>
</li>
<li><p>Update the RestaurantService class declaration so it implements the IRestaurantService we just created:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> MongoDB.Bson;
<span class="hljs-keyword">using</span> MongoDB.Driver;
<span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Services</span>
{
  <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">RestaurantService</span> : <span class="hljs-title">IRestaurantService</span>
  {
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> RestaurantReservationDbContext _restaurantDbContext;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">RestaurantService</span>(<span class="hljs-params">RestaurantReservationDbContext restaurantDbContext</span>)</span>
    {
        _restaurantDbContext = restaurantDbContext;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddRestaurant</span>(<span class="hljs-params">Restaurant restaurant</span>)</span>
    {
      _restaurantDbContext.Restaurants.Add(restaurant);

      _restaurantDbContext.ChangeTracker.DetectChanges();
      Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);

      _restaurantDbContext.SaveChanges();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DeleteRestaurant</span>(<span class="hljs-params">Restaurant restaurant</span>)</span>
    {
      <span class="hljs-keyword">var</span> restaurantToDelete = _restaurantDbContext.Restaurants.Where(c =&gt; c.Id == restaurant.Id).FirstOrDefault();

      <span class="hljs-keyword">if</span>(restaurantToDelete != <span class="hljs-literal">null</span>) {
          _restaurantDbContext.Restaurants.Remove(restaurantToDelete);
        _restaurantDbContext.ChangeTracker.DetectChanges();
          Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);
          _restaurantDbContext.SaveChanges();
          }
        <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">"The restaurant to delete cannot be found."</span>);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">EditRestaurant</span>(<span class="hljs-params">Restaurant restaurant</span>)</span>
    {
          <span class="hljs-keyword">var</span> restaurantToUpdate = _restaurantDbContext.Restaurants.FirstOrDefault(c =&gt; c.Id == restaurant.Id);

        <span class="hljs-keyword">if</span>(restaurantToUpdate != <span class="hljs-literal">null</span>)
        {                
            restaurantToUpdate.name = restaurant.name;
            restaurantToUpdate.cuisine = restaurant.cuisine;
            restaurantToUpdate.borough = restaurant.borough;

            _restaurantDbContext.Restaurants.Update(restaurantToUpdate);

            _restaurantDbContext.ChangeTracker.DetectChanges();
            Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);

            _restaurantDbContext.SaveChanges();

        }
      <span class="hljs-keyword">else</span>
        {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">"The restaurant to update cannot be found. "</span>);
        }
    }        

    <span class="hljs-function"><span class="hljs-keyword">public</span> IEnumerable&lt;Restaurant&gt; <span class="hljs-title">GetAllRestaurants</span>(<span class="hljs-params"></span>)</span>
    {
      <span class="hljs-keyword">return</span> _restaurantDbContext.Restaurants.OrderByDescending(c =&gt; c.Id).Take(<span class="hljs-number">20</span>).AsNoTracking().AsEnumerable&lt;Restaurant&gt;();
    }

    <span class="hljs-keyword">public</span> Restaurant? GetRestaurantById(ObjectId id)
    {
      <span class="hljs-keyword">return</span> _restaurantDbContext.Restaurants.FirstOrDefault(c  =&gt; c.Id == id);
    }
  }

}
</code></pre>
<h3 id="heading-ireservationservice-and-reservationservice">IReservationService and ReservationService</h3>
<p>Next up is our IReservationService and ReservationService.</p>
<p>Create the IReservationService interface and add the following methods:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> MongoDB.Bson;
<span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IReservationService</span>
    {
        <span class="hljs-function">IEnumerable&lt;Reservation&gt; <span class="hljs-title">GetAllReservations</span>(<span class="hljs-params"></span>)</span>;
        Reservation? GetReservationById(ObjectId id);

        <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">AddReservation</span>(<span class="hljs-params">Reservation newReservation</span>)</span>;

        <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">EditReservation</span>(<span class="hljs-params">Reservation updatedReservation</span>)</span>;

        <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">DeleteReservation</span>(<span class="hljs-params">Reservation reservationToDelete</span>)</span>;
    }
}
</code></pre>
<p>Create the ReservationService class, and replace your class with the following code that implements all the methods:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.EntityFrameworkCore;
<span class="hljs-keyword">using</span> MongoDB.Bson;
<span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Services</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ReservationService</span> : <span class="hljs-title">IReservationService</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> RestaurantReservationDbContext _restaurantDbContext;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ReservationService</span>(<span class="hljs-params">RestaurantReservationDbContext restaurantDbContext</span>)</span>
        {
            _restaurantDbContext = restaurantDbContext;
        }
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">AddReservation</span>(<span class="hljs-params">Reservation newReservation</span>)</span>
        {
            <span class="hljs-keyword">var</span> bookedRestaurant = _restaurantDbContext.Restaurants.FirstOrDefault(c =&gt; c.Id == newReservation.RestaurantId);
            <span class="hljs-keyword">if</span> (bookedRestaurant == <span class="hljs-literal">null</span>)
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">"The restaurant to be reserved cannot be found."</span>);
            }

            newReservation.RestaurantName = bookedRestaurant.name;

            _restaurantDbContext.Reservations.Add(newReservation);

            _restaurantDbContext.ChangeTracker.DetectChanges();
            Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);

            _restaurantDbContext.SaveChanges();
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DeleteReservation</span>(<span class="hljs-params">Reservation reservation</span>)</span>
        {
            <span class="hljs-keyword">var</span> reservationToDelete = _restaurantDbContext.Reservations.FirstOrDefault(b =&gt; b.Id == reservation.Id);

            <span class="hljs-keyword">if</span>(reservationToDelete != <span class="hljs-literal">null</span>)
            {
                _restaurantDbContext.Reservations.Remove(reservationToDelete);

                _restaurantDbContext.ChangeTracker.DetectChanges();
                Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);

                _restaurantDbContext.SaveChanges();
            }
            <span class="hljs-keyword">else</span>
            {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">"The reservation to delete cannot be found."</span>);
            }
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">EditReservation</span>(<span class="hljs-params">Reservation updatedReservation</span>)</span>
        {
           <span class="hljs-keyword">var</span> reservationToUpdate = _restaurantDbContext.Reservations.FirstOrDefault(b =&gt; b.Id == updatedReservation.Id);


            <span class="hljs-keyword">if</span> (reservationToUpdate != <span class="hljs-literal">null</span>)
            {               
                reservationToUpdate.date = updatedReservation.date;

                _restaurantDbContext.Reservations.Update(reservationToUpdate);

                _restaurantDbContext.ChangeTracker.DetectChanges();
                _restaurantDbContext.SaveChanges();

                Console.WriteLine(_restaurantDbContext.ChangeTracker.DebugView.LongView);
            }  
            <span class="hljs-keyword">else</span> 
            { 
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentException(<span class="hljs-string">"Reservation to be updated cannot be found"</span>);
            }

        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> IEnumerable&lt;Reservation&gt; <span class="hljs-title">GetAllReservations</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">return</span> _restaurantDbContext.Reservations.OrderBy(b =&gt; b.date).Take(<span class="hljs-number">20</span>).AsNoTracking().AsEnumerable&lt;Reservation&gt;();
        }

        <span class="hljs-keyword">public</span> Reservation? GetReservationById(ObjectId id)
        {
            <span class="hljs-keyword">return</span> _restaurantDbContext.Reservations.AsNoTracking().FirstOrDefault(b =&gt; b.Id == id);
        }

    }
}
</code></pre>
<p>This code is very similar to the code for the RestaurantService class but for reservations instead.</p>
<h3 id="heading-adding-them-to-dependency-injection">Adding them to Dependency Injection</h3>
<p>The final step for the services is to add them to the dependency injection container.</p>
<p>Inside Program.cs, add the following code after the code we added there earlier:</p>
<pre><code class="lang-csharp">builder.Services.AddScoped&lt;IRestaurantService, RestaurantService&gt;();
builder.Services.AddScoped&lt;IReservationService, ReservationService&gt;();
</code></pre>
<h2 id="heading-creating-the-view-models">Creating the view models</h2>
<p>Before we implement the front end, we need to add the view models that will act as a messenger between our front and back ends where required. Even though our application is quite simple, implementing the view model is still good practice as it helps decouple the pieces of the app.</p>
<h3 id="heading-restaurantlistviewmodel">RestaurantListViewModel</h3>
<p>The first one we will add is the RestaurantListViewModel. This will be used as the model in our Razor page later on for listing restaurants in our database.</p>
<ol>
<li><p>Create a new folder in the root of the project called ViewModels.</p>
</li>
<li><p>Add a new file called RestaurantListViewModel.cs.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.ViewModels</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">RestaurantListViewModel</span>
    {        
        <span class="hljs-keyword">public</span> IEnumerable&lt;Restaurant&gt;? Restaurants { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<h3 id="heading-restaurantaddviewmodel">RestaurantAddViewModel</h3>
<p>We also want a view model that can be used by the Add view we will add later.</p>
<ol>
<li><p>Inside the ViewModels folder, create a new file called RestaurantAddViewMode.cs.</p>
</li>
<li><p>Add:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.ViewModels</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">RestaurantAddViewModel</span>
    {
        <span class="hljs-keyword">public</span> Restaurant? Restaurant { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } 
    }
}
</code></pre>
<h3 id="heading-reservationlistviewmodel">ReservationListViewModel</h3>
<p>Now, we want to do something very similar for reservations, starting with ReservationListViewModel.</p>
<ol>
<li><p>Create a new file in the ViewModels folder called ReservationListViewModel.cs.</p>
</li>
<li><p>Add:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.ViewModels</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ReservationListViewModel</span>
    {
        <span class="hljs-keyword">public</span> IEnumerable&lt;Reservation&gt;? Reservations { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<h3 id="heading-reservationaddviewmodel">ReservationAddViewModel</h3>
<p>Finally, we have our ReservationAddViewModel.</p>
<p>Create the file and add this code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> RestRes.Models;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.ViewModels</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ReservationAddViewModel</span>
    {
        <span class="hljs-keyword">public</span> Reservation? Reservation { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
}
</code></pre>
<h3 id="heading-adding-to-viewimports">Adding to _ViewImports</h3>
<p>Later on, we will be adding references to our models and viewmodels in the views. In order for the application to know what they are, we need to add references to them in the _ViewImports.cshtml file inside the Views folder.</p>
<p>There will already be some references in there, including TagHelpers, so we want to add references to our .Models and .ViewModels folders. So the top of the file should look like this:</p>
<pre><code class="lang-csharp">@using RestRes
@using RestRes.Models
@using RestRes.ViewModels
</code></pre>
<h2 id="heading-creating-the-controllers">Creating the controllers</h2>
<p>Now that we have the backend implementation and the view models we will refer to, we can start working toward the front end. We will be creating two controllers: one for Restaurant and one for Reservation.</p>
<h3 id="heading-restaurantcontroller">RestaurantController</h3>
<p>The first controller we will add is for the restaurant.</p>
<ol>
<li><p>Inside the existing Controllers folder, add a new controller file called RestaurantController.cs. If using Visual Studio, use the MVC Controller - Empty controller template.</p>
</li>
<li><p>Add this code:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;
<span class="hljs-keyword">using</span> MongoDB.Bson;
<span class="hljs-keyword">using</span> RestRes.Models;
<span class="hljs-keyword">using</span> RestRes.Services;
<span class="hljs-keyword">using</span> RestRes.ViewModels;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Controllers</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">RestaurantController</span> : <span class="hljs-title">Controller</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IRestaurantService _RestaurantService;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">RestaurantController</span>(<span class="hljs-params">IRestaurantService RestaurantService</span>)</span>
        {
            _RestaurantService = RestaurantService;
        }
        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Index</span>(<span class="hljs-params"></span>)</span>
        {
            RestaurantListViewModel viewModel = <span class="hljs-keyword">new</span>()
            {
                Restaurants = _RestaurantService.GetAllRestaurants(),
            };
            <span class="hljs-keyword">return</span> View(viewModel);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Add</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">return</span> View();
        }

        [<span class="hljs-meta">HttpPost</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Add</span>(<span class="hljs-params">RestaurantAddViewModel restaurantAddViewModel</span>)</span>
        {
            <span class="hljs-keyword">if</span>(ModelState.IsValid)
            {
                Restaurant newRestaurant = <span class="hljs-keyword">new</span>()
                {
                    name = restaurantAddViewModel.Restaurant.name,
                    borough = restaurantAddViewModel.Restaurant.borough,
                    cuisine = restaurantAddViewModel.Restaurant.cuisine
                };

                _RestaurantService.AddRestaurant(newRestaurant);
                <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Index"</span>);
            }

            <span class="hljs-keyword">return</span> View(restaurantAddViewModel);         
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Edit</span>(<span class="hljs-params">ObjectId id</span>)</span>
        {
            <span class="hljs-keyword">if</span>(id == <span class="hljs-literal">null</span> || id == ObjectId.Empty)
            {
                <span class="hljs-keyword">return</span> NotFound();
            }

            <span class="hljs-keyword">var</span> selectedRestaurant = _RestaurantService.GetRestaurantById(id);
            <span class="hljs-keyword">return</span> View(selectedRestaurant);
        }

        [<span class="hljs-meta">HttpPost</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Edit</span>(<span class="hljs-params">Restaurant restaurant</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">if</span>(ModelState.IsValid)
                {
                    _RestaurantService.EditRestaurant(restaurant);
                    <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Index"</span>);
                }
                <span class="hljs-keyword">else</span>
                {
                    <span class="hljs-keyword">return</span> BadRequest();
                }
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                ModelState.AddModelError(<span class="hljs-string">""</span>, <span class="hljs-string">$"Updating the restaurant failed, please try again! Error: <span class="hljs-subst">{ex.Message}</span>"</span>);
            }

            <span class="hljs-keyword">return</span> View(restaurant);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Delete</span>(<span class="hljs-params">ObjectId id</span>)</span> {
            <span class="hljs-keyword">if</span> (id == <span class="hljs-literal">null</span> || id == ObjectId.Empty)
            {
                <span class="hljs-keyword">return</span> NotFound();
            }

            <span class="hljs-keyword">var</span> selectedRestaurant = _RestaurantService.GetRestaurantById(id);
            <span class="hljs-keyword">return</span> View(selectedRestaurant);
        }

        [<span class="hljs-meta">HttpPost</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Delete</span>(<span class="hljs-params">Restaurant restaurant</span>)</span>
        {
            <span class="hljs-keyword">if</span> (restaurant.Id == ObjectId.Empty)
            {
                ViewData[<span class="hljs-string">"ErrorMessage"</span>] = <span class="hljs-string">"Deleting the restaurant failed, invalid ID!"</span>;
                <span class="hljs-keyword">return</span> View();
            }

            <span class="hljs-keyword">try</span>
            {
                _RestaurantService.DeleteRestaurant(restaurant);
                TempData[<span class="hljs-string">"RestaurantDeleted"</span>] = <span class="hljs-string">"Restaurant deleted successfully!"</span>;

                <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Index"</span>);
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                ViewData[<span class="hljs-string">"ErrorMessage"</span>] = <span class="hljs-string">$"Deleting the restaurant failed, please try again! Error: <span class="hljs-subst">{ex.Message}</span>"</span>;
            }

            <span class="hljs-keyword">var</span> selectedRestaurant = _RestaurantService.GetRestaurantById(restaurant.Id);
            <span class="hljs-keyword">return</span> View(selectedRestaurant);
        }        
    }
}
</code></pre>
<h3 id="heading-reservationcontroller">ReservationController</h3>
<p>Now for the reservation controller. This is very similar to the RestaurantController but it has a reference to both the restaurant and reservation service as we need to associate a restaurant with a reservation. This is because at the moment, the EF Core Provider doesn’t support relationships between entities so we can relate entities in a different way.</p>
<ol>
<li><p>Create another empty MVC Controller file called ReservationController.cs.</p>
</li>
<li><p>Paste the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;
<span class="hljs-keyword">using</span> MongoDB.Bson;
<span class="hljs-keyword">using</span> RestRes.Models;
<span class="hljs-keyword">using</span> RestRes.Services;
<span class="hljs-keyword">using</span> RestRes.ViewModels;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">RestRes.Controllers</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ReservationController</span> : <span class="hljs-title">Controller</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IReservationService _ReservationService;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IRestaurantService _RestaurantService;        

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ReservationController</span>(<span class="hljs-params">IReservationService ReservationService, IRestaurantService RestaurantService</span>)</span>
        {
            _ReservationService = ReservationService;
            _RestaurantService = RestaurantService;
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Index</span>(<span class="hljs-params"></span>)</span>
        {
            ReservationListViewModel viewModel = <span class="hljs-keyword">new</span> ReservationListViewModel()
            {
                Reservations = _ReservationService.GetAllReservations()
            };
            <span class="hljs-keyword">return</span> View(viewModel);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Add</span>(<span class="hljs-params">ObjectId restaurantId</span>)</span>
        {
            <span class="hljs-keyword">var</span> selectedRestaurant = _RestaurantService.GetRestaurantById(restaurantId);

            ReservationAddViewModel reservationAddViewModel = <span class="hljs-keyword">new</span> ReservationAddViewModel();

            reservationAddViewModel.Reservation = <span class="hljs-keyword">new</span> Reservation();
            reservationAddViewModel.Reservation.RestaurantId = selectedRestaurant.Id;
            reservationAddViewModel.Reservation.RestaurantName = selectedRestaurant.name;
            reservationAddViewModel.Reservation.date = DateTime.UtcNow;

            <span class="hljs-keyword">return</span> View(reservationAddViewModel);
        }

        [<span class="hljs-meta">HttpPost</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Add</span>(<span class="hljs-params">ReservationAddViewModel reservationAddViewModel</span>)</span>
        {
                Reservation newReservation = <span class="hljs-keyword">new</span>()
                {
                    RestaurantId = reservationAddViewModel.Reservation.RestaurantId,                   
                    date = reservationAddViewModel.Reservation.date,
                };

                _ReservationService.AddReservation(newReservation);
                <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Index"</span>);   
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Edit</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Id</span>)</span>
        {
            <span class="hljs-keyword">if</span>(Id == <span class="hljs-literal">null</span> || <span class="hljs-keyword">string</span>.IsNullOrEmpty(Id))
            {
                <span class="hljs-keyword">return</span> NotFound();
            }

            <span class="hljs-keyword">var</span> selectedReservation = _ReservationService.GetReservationById(<span class="hljs-keyword">new</span> ObjectId(Id));
            <span class="hljs-keyword">return</span> View(selectedReservation);
        }

        [<span class="hljs-meta">HttpPost</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Edit</span>(<span class="hljs-params">Reservation reservation</span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">var</span> existingReservation = _ReservationService.GetReservationById(reservation.Id);
                <span class="hljs-keyword">if</span> (existingReservation != <span class="hljs-literal">null</span>)
                {
                    _ReservationService.EditReservation(reservation);
                    <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Index"</span>);
                }
                <span class="hljs-keyword">else</span>
                {
                    ModelState.AddModelError(<span class="hljs-string">""</span>, <span class="hljs-string">$"Reservation with ID <span class="hljs-subst">{reservation.Id}</span> does not exist!"</span>);
                }
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                ModelState.AddModelError(<span class="hljs-string">""</span>, <span class="hljs-string">$"Updating the reservation failed, please try again! Error: <span class="hljs-subst">{ex.Message}</span>"</span>);
            }

            <span class="hljs-keyword">return</span> View(reservation);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Delete</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> Id</span>)</span>
        {
            <span class="hljs-keyword">if</span> (Id == <span class="hljs-literal">null</span> || <span class="hljs-keyword">string</span>.IsNullOrEmpty(Id))
            {
                <span class="hljs-keyword">return</span> NotFound();
            }

            <span class="hljs-keyword">var</span> selectedReservation = _ReservationService.GetReservationById(<span class="hljs-keyword">new</span> ObjectId(Id));
            <span class="hljs-keyword">return</span> View(selectedReservation);
        }

        [<span class="hljs-meta">HttpPost</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">Delete</span>(<span class="hljs-params">Reservation reservation</span>)</span>
        {
            <span class="hljs-keyword">if</span>(reservation.Id == <span class="hljs-literal">null</span>)
            {
                ViewData[<span class="hljs-string">"ErrorMessage"</span>] = <span class="hljs-string">"Deleting the reservation failed, invalid ID!"</span>;
                <span class="hljs-keyword">return</span> View();
            }

            <span class="hljs-keyword">try</span>
            {
                _ReservationService.DeleteReservation(reservation);
                TempData[<span class="hljs-string">"ReservationDeleted"</span>] = <span class="hljs-string">"Reservation deleted successfully"</span>;

                <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Index"</span>);
            }
            <span class="hljs-keyword">catch</span> (Exception ex)
            {
                ViewData[<span class="hljs-string">"ErrorMessage"</span>] = <span class="hljs-string">$"Deleting the reservation failed, please try again! Error: <span class="hljs-subst">{ex.Message}</span>"</span>;
            }

            <span class="hljs-keyword">var</span> selectedRestaurant = _ReservationService.GetReservationById(reservation.Id);
            <span class="hljs-keyword">return</span> View(selectedRestaurant);
        }
    }
}
</code></pre>
<h2 id="heading-creating-the-views">Creating the views</h2>
<p>Now we have the back end and the controllers prepped with the endpoints for our restaurant reservation system, it is time to implement the views. This will be using Razor pages. You will also see reference to classes from Bootstrap as this is the CSS framework that comes with MVC applications out of the box. We will be providing views for the CRUD operations for both listings and bookings.</p>
<h3 id="heading-listing-restaurants">Listing Restaurants</h3>
<p>First, we will provide a view that will map to the root of /Restaurant, which will by convention look at the Index method we implemented.</p>
<p><a target="_blank" href="http://ASP.NET">ASP.NET</a> Core MVC uses a convention pattern whereby you name the .cshtml file the name of the endpoint/method it uses and it lives inside a folder named after its controller.</p>
<ol>
<li><p>Inside the Views folder, create a new subfolder called Restaurant.</p>
</li>
<li><p>Inside that Restaurant folder, add a new view by creating a file called <code>Index.cshtml</code>. If using the available templates, you want Razor View - Empty. Name the view Index.</p>
</li>
<li><p>Add this code:</p>
</li>
</ol>
<pre><code class="lang-csharp">@model RestaurantListViewModel

@if (TempData[<span class="hljs-string">"RestaurantDeleted"</span>] != <span class="hljs-literal">null</span>)
{
    &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-success"</span>&gt;@TempData[<span class="hljs-string">"RestaurantDeleted"</span>]&lt;/p&gt;
}


@if (!Model.Restaurants.Any())
{
    &lt;p&gt;No results&lt;/p&gt;
}
<span class="hljs-keyword">else</span>
{
    &lt;table <span class="hljs-keyword">class</span>=<span class="hljs-string">"table table-condensed table-bordered"</span>&gt;
        &lt;tr&gt;
            &lt;th&gt;
                Name
            &lt;/th&gt;
            &lt;th&gt;
                Cuisine
            &lt;/th&gt;
            &lt;th&gt;
                Borough
            &lt;/th&gt;            
            &lt;th&gt;
                Actions
            &lt;/th&gt;
        &lt;/tr&gt;

        @foreach (<span class="hljs-keyword">var</span> restaurant <span class="hljs-keyword">in</span> Model.Restaurants)
        {
            &lt;tr&gt;
                &lt;td&gt;@restaurant.name&lt;/td&gt;
                &lt;td&gt;@restaurant.cuisine&lt;/td&gt;
                &lt;td&gt;@restaurant.borough&lt;/td&gt;                
                &lt;td&gt;
                    &lt;a asp-action=<span class="hljs-string">"Edit"</span> asp-route-id=<span class="hljs-string">"@restaurant.Id.ToString()"</span>&gt;Edit&lt;/a&gt;
                    &lt;a asp-action=<span class="hljs-string">"Delete"</span> asp-route-id=<span class="hljs-string">"@restaurant.Id.ToString()"</span>&gt;Delete&lt;/a&gt;
                    &lt;a asp-controller=<span class="hljs-string">"Reservation"</span> asp-action=<span class="hljs-string">"Add"</span> asp-route-restaurantId=<span class="hljs-string">"@restaurant.Id.ToString()"</span>&gt;Reserve&lt;/a&gt;
                &lt;/td&gt;
            &lt;/tr&gt;
        }

    &lt;/table&gt;
}

&lt;p&gt;
    &lt;a <span class="hljs-keyword">class</span>=<span class="hljs-string">"btn btn-primary"</span> asp-action=<span class="hljs-string">"Add"</span>&gt;Add <span class="hljs-keyword">new</span> restaurant&lt;/a&gt;
&lt;/p&gt;
</code></pre>
<p>Now let's update the default route from Home to /Restaurant.</p>
<p>In Program.cs, inside <code>app.MapControllerRoute</code>, replace the pattern line with the following:</p>
<pre><code class="lang-csharp">pattern: <span class="hljs-string">"{controller=Restaurant}/{action=Index}/{id?}"</span>);
</code></pre>
<p>If we ran this now, the buttons would lead to 404s because we haven’t implemented them yet. So let’s do that now.</p>
<h3 id="heading-adding-restaurants">Adding restaurants</h3>
<p>We will start with the form for adding new restaurants.</p>
<ol>
<li><p>Add a new, empty Razor View inside the Restaurant subfolder called Add.cshtml.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp">@model RestaurantAddViewModel

&lt;h2&gt;Create a <span class="hljs-keyword">new</span> restaurant&lt;/h2&gt;
&lt;hr /&gt;

@if (ViewData[<span class="hljs-string">"ErrorMessage"</span>] != <span class="hljs-literal">null</span>)
{
    &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;@ViewData[<span class="hljs-string">"ErrorMessage"</span>]&lt;/p&gt;
}

&lt;form method=<span class="hljs-string">"post"</span> asp-controller=<span class="hljs-string">"Restaurant"</span> asp-action=<span class="hljs-string">"Add"</span>&gt;
    &lt;div asp-validation-summary=<span class="hljs-string">"All"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;&lt;/div&gt;

    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"mb-3"</span>&gt;
        &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.name"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-label"</span>&gt;&lt;/label&gt;
        &lt;input asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.name"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-control"</span> /&gt;
        &lt;span asp-validation-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.name"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"mb-3"</span>&gt;
        &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.cuisine"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-label"</span>&gt;&lt;/label&gt;
        &lt;input asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.cuisine"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-control"</span> /&gt;
        &lt;span asp-validation-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.cuisine"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;&lt;/span&gt;
    &lt;/div&gt;

      &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"mb-3"</span>&gt;
        &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.borough"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-label"</span>&gt;Borough&lt;/label&gt;
        &lt;input asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.borough"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-control"</span> /&gt;
        &lt;span asp-validation-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Restaurant.borough"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;input type=<span class="hljs-string">"submit"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"Add restaurant"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"btn btn-primary"</span> /&gt;
&lt;/form&gt;

&lt;div&gt;
    &lt;a asp-controller=<span class="hljs-string">"Restaurant"</span> asp-action=<span class="hljs-string">"Index"</span>&gt;Back to list&lt;/a&gt;
&lt;/div&gt;
</code></pre>
<h3 id="heading-editing-restaurants">Editing restaurants</h3>
<p>The code for the Edit page is almost identical to Add, but it uses the Restaurant as a model as it will use the restaurant it is passed to pre-populate the form for editing.</p>
<ol>
<li><p>Add another view inside the Restaurant subfolder called Edit.cshtml.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp">@model Restaurant

&lt;h2&gt;Update @Model.name&lt;/h2&gt;
&lt;hr /&gt;

&lt;form method=<span class="hljs-string">"post"</span> asp-controller=<span class="hljs-string">"Restaurant"</span> asp-action=<span class="hljs-string">"Edit"</span>&gt;
    &lt;div asp-validation-summary=<span class="hljs-string">"ModelOnly"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;&lt;/div&gt;
    &lt;input type=<span class="hljs-string">"hidden"</span> asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Id"</span> /&gt;

    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"mb-3"</span>&gt;
        &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"name"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-label"</span>&gt;Name&lt;/label&gt;
        &lt;input asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"name"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-control"</span> /&gt;
        &lt;span asp-validation-<span class="hljs-keyword">for</span>=<span class="hljs-string">"name"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>/&gt;
    &lt;/div&gt;
    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"mb-3"</span>&gt;
        &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"cuisine"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-label"</span>&gt;&lt;/label&gt;
        &lt;input asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"cuisine"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-control"</span> /&gt;
        &lt;span asp-validation-<span class="hljs-keyword">for</span>=<span class="hljs-string">"cuisine"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>/&gt;
    &lt;/div&gt;
    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"mb-3"</span>&gt;
        &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"borough"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-label"</span>&gt;Borough&lt;/label&gt;
        &lt;input asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"borough"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-control"</span> /&gt;
        &lt;span asp-validation-<span class="hljs-keyword">for</span>=<span class="hljs-string">"borough"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>/&gt;
    &lt;/div&gt;
    &lt;input type=<span class="hljs-string">"submit"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"Update restaurant"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"btn btn-primary"</span> /&gt;
&lt;/form&gt;
&lt;div&gt;
    &lt;a asp-controller=<span class="hljs-string">"Restaurant"</span> asp-action=<span class="hljs-string">"Index"</span>&gt;Back to list&lt;/a&gt;
&lt;/div&gt;
</code></pre>
<h3 id="heading-deleting-restaurants">Deleting restaurants</h3>
<p>The final page we need to implement is the page that is called when the delete button is clicked.</p>
<ol>
<li><p>Create a new empty View called Delete.cshtml.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp">@model Restaurant

&lt;h2&gt;Deleting @Model.name&lt;/h2&gt;
&lt;hr /&gt;

@if(ViewData[<span class="hljs-string">"ErrorMessage"</span>] != <span class="hljs-literal">null</span>)
{
    &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;@ViewData[<span class="hljs-string">"ErrorMessage"</span>]&lt;/p&gt;
}

&lt;div&gt;
    &lt;dl <span class="hljs-keyword">class</span>=<span class="hljs-string">"row"</span>&gt;
        &lt;dt <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-4"</span>&gt;
            &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"name"</span>&gt;Name&lt;/label&gt;
        &lt;/dt&gt;
        &lt;dd <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-10"</span>&gt;
            @Model?.name
        &lt;/dd&gt;
        &lt;dt <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-2"</span>&gt;
            &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"cuisine"</span>&gt;&lt;/label&gt;
        &lt;/dt&gt;
        &lt;dd <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-10"</span>&gt;
            @Model?.cuisine
        &lt;/dd&gt;
        &lt;dt <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-2"</span>&gt;
            &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"borough"</span>&gt;Borough&lt;/label&gt;
        &lt;/dt&gt;
        &lt;dd <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-10"</span>&gt;
            @Model?.borough
        &lt;/dd&gt;

    &lt;/dl&gt;
&lt;/div&gt;

&lt;form method=<span class="hljs-string">"post"</span> asp-action=<span class="hljs-string">"Delete"</span>&gt;
    &lt;input type=<span class="hljs-string">"hidden"</span> asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Id"</span> /&gt;
    &lt;input type=<span class="hljs-string">"submit"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"Delete restaurant"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"btn btn-danger"</span> onclick=<span class="hljs-string">"javascript: return confirm('Are you sure you want to delete this restaurant?');"</span> /&gt;
&lt;/form&gt;

&lt;div&gt;
    &lt;a asp-controller=<span class="hljs-string">"Restaurant"</span> asp-action=<span class="hljs-string">"Index"</span>&gt;Back to list&lt;/a&gt;
&lt;/div&gt;
</code></pre>
<h3 id="heading-listing-reservations">Listing reservations</h3>
<p>We have added the views for the restaurants so now we will add the views for reservations, starting with listing any existing reservations.</p>
<ol>
<li><p>Create a new folder inside the Views folder called Reservation.</p>
</li>
<li><p>Create a new empty view file called Index.cshtml.</p>
</li>
<li><p>Add the following code to display the reservations, if any exist:</p>
</li>
</ol>
<pre><code class="lang-csharp">@model ReservationListViewModel

@if (TempData[<span class="hljs-string">"ReservationDeleted"</span>] != <span class="hljs-literal">null</span>)
{
    &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-success"</span>&gt;@TempData[<span class="hljs-string">"ReservationDeleted"</span>]&lt;/p&gt;
}

@if (!Model.Reservations.Any())
{
    &lt;p&gt;No results&lt;/p&gt;
}

<span class="hljs-keyword">else</span>
{    
    &lt;table <span class="hljs-keyword">class</span>=<span class="hljs-string">"table table-condensed table-bordered"</span>&gt;
        &lt;tr&gt;
            &lt;th&gt;
                Booked Restaurant
            &lt;/th&gt;
            &lt;th&gt;
                Date and Time
            &lt;/th&gt;
            &lt;th&gt;
                Actions
            &lt;/th&gt;
        &lt;/tr&gt;

        @foreach(<span class="hljs-keyword">var</span> reservation <span class="hljs-keyword">in</span> Model.Reservations)
        {
            &lt;tr&gt;
                &lt;td&gt;@reservation.RestaurantName&lt;/td&gt;
                &lt;td&gt;@reservation.date.ToLocalTime()&lt;/td&gt;
                &lt;td&gt;
                    &lt;a asp-action=<span class="hljs-string">"Edit"</span> asp-route-id=<span class="hljs-string">"@reservation.Id.ToString()"</span>&gt;Edit&lt;/a&gt;
                    &lt;a asp-action=<span class="hljs-string">"Delete"</span> asp-route-id=<span class="hljs-string">"@reservation.Id.ToString()"</span>&gt;Delete&lt;/a&gt;
                &lt;/td&gt;
            &lt;/tr&gt;
        }

    &lt;/table&gt;   

}
</code></pre>
<h3 id="heading-adding-reservations">Adding reservations</h3>
<p>Adding reservations is next.</p>
<ol>
<li><p>Create an empty view called Add.cshtml.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp">@model ReservationAddViewModel


@if (ViewData[<span class="hljs-string">"ErrorMessage"</span>] != <span class="hljs-literal">null</span>)
{
    &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;@ViewData[<span class="hljs-string">"ErrorMessage"</span>]&lt;/p&gt;
}

&lt;form method=<span class="hljs-string">"post"</span> asp-controller=<span class="hljs-string">"Reservation"</span> asp-action=<span class="hljs-string">"Add"</span>&gt;
    &lt;div asp-validation-summary=<span class="hljs-string">"All"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;&lt;/div&gt;
    &lt;input type=<span class="hljs-string">"hidden"</span> asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Reservation.Id"</span> /&gt;
    &lt;input type=<span class="hljs-string">"hidden"</span> asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Reservation.RestaurantId"</span> /&gt;

    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"mb-3"</span>&gt;
        &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Reservation.date"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-label"</span>&gt;&lt;/label&gt;
        &lt;input asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Reservation.date"</span> type=<span class="hljs-string">"datetime-local"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"@DateTime.Now.ToString("</span>yyyy-MM-ddTHH:mm<span class="hljs-string">")"</span> /&gt;
        &lt;span asp-validation-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Reservation.date"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;input type=<span class="hljs-string">"submit"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"Reserve table"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"btn btn-primary"</span> /&gt;
&lt;/form&gt;
</code></pre>
<h3 id="heading-editing-reservations">Editing reservations</h3>
<p>Editing reservations is next.</p>
<ol>
<li><p>Create an empty view called Edit.cshtml.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp">@model Reservation

&lt;h2&gt;Editing reservation <span class="hljs-keyword">for</span> @Model.RestaurantName <span class="hljs-keyword">on</span> @Model.date.ToLocalTime()&lt;/h2&gt;
&lt;hr /&gt;

&lt;form method=<span class="hljs-string">"post"</span> asp-controller=<span class="hljs-string">"Reservation"</span> asp-action=<span class="hljs-string">"Edit"</span>&gt;
    &lt;div asp-validation-summary=<span class="hljs-string">"ModelOnly"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;&lt;/div&gt;
    &lt;input type=<span class="hljs-string">"hidden"</span> asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Id"</span> /&gt;

    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"mb-3"</span>&gt;
        &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"date"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-label"</span>&gt;&lt;/label&gt;
        &lt;input asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"date"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"@Model.date.ToLocalTime().ToString("</span>yyyy-MM-ddTHH:mm<span class="hljs-string">")"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"form-control"</span> /&gt;
        &lt;span asp-validation-<span class="hljs-keyword">for</span>=<span class="hljs-string">"date"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span> /&gt;
    &lt;/div&gt;
    &lt;input type=<span class="hljs-string">"submit"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"Update reservation"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"btn btn-primary"</span> /&gt;
&lt;/form&gt;
&lt;div&gt;
    &lt;a asp-controller=<span class="hljs-string">"Reservation"</span> asp-action=<span class="hljs-string">"Index"</span>&gt;Back to reservations&lt;/a&gt;
&lt;/div&gt;
</code></pre>
<h3 id="heading-deleting-reservations">Deleting reservations</h3>
<p>Deleting reservations is next.</p>
<ol>
<li><p>Create an empty view called Delete.cshtml.</p>
</li>
<li><p>Add the following code:</p>
</li>
</ol>
<pre><code class="lang-csharp">@model Reservation

&lt;h2&gt;Delete reservation&lt;/h2&gt;
&lt;hr /&gt;

@if (ViewData[<span class="hljs-string">"ErrorMessage"</span>] != <span class="hljs-literal">null</span>)
{
    &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-danger"</span>&gt;@ViewData[<span class="hljs-string">"ErrorMessage"</span>]&lt;/p&gt;
}

&lt;div&gt;
    &lt;dl <span class="hljs-keyword">class</span>=<span class="hljs-string">"row"</span>&gt;
        &lt;dt <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-2"</span>&gt;
            &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"RestaurantName"</span>&gt;Name&lt;/label&gt;
        &lt;/dt&gt;
        &lt;dd <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-10"</span>&gt;
            @Model?.RestaurantName
        &lt;/dd&gt;
        &lt;dt <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-2"</span>&gt;
            &lt;label asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"date"</span>&gt;&lt;/label&gt;
        &lt;/dt&gt;
        &lt;dd <span class="hljs-keyword">class</span>=<span class="hljs-string">"col-sm-10"</span>&gt;
            @Model?.date.ToLocalTime()
        &lt;/dd&gt;
        &lt;/dl&gt;
&lt;/div&gt;

&lt;form method=<span class="hljs-string">"post"</span> asp-action=<span class="hljs-string">"Delete"</span>&gt;
    &lt;input type=<span class="hljs-string">"hidden"</span> asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"Id"</span> /&gt;
    &lt;input type=<span class="hljs-string">"hidden"</span> asp-<span class="hljs-keyword">for</span>=<span class="hljs-string">"RestaurantId"</span> /&gt;
    &lt;input type=<span class="hljs-string">"submit"</span> <span class="hljs-keyword">value</span>=<span class="hljs-string">"Delete reservation"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"btn btn-danger"</span> onclick=<span class="hljs-string">"javascript: return confirm('Are you sure you want to delete this reservation?');"</span> /&gt;
&lt;/form&gt;

&lt;div&gt;
    &lt;a asp-controller=<span class="hljs-string">"Reservation"</span> asp-action=<span class="hljs-string">"Index"</span>&gt;Back to list&lt;/a&gt;
&lt;/div&gt;
</code></pre>
<h2 id="heading-updating-navbar">Updating NavBar</h2>
<p>The final thing to add is to update the navigation bar of the application so we can easily switch between restaurants and reservations.</p>
<p>Navigate to the file at <code>Views/Shared/_Layout.cshtml</code>. Find the <code>div</code> with class <code>navbar-collapse</code>. Remove that entire section and add the following code:</p>
<pre><code class="lang-csharp">&lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"collapse navbar-collapse justify-content-between"</span>&gt;
    &lt;ul <span class="hljs-keyword">class</span>=<span class="hljs-string">"navbar-nav flex-grow-1"</span>&gt;
        &lt;li <span class="hljs-keyword">class</span>=<span class="hljs-string">"nav-item"</span>&gt;
            &lt;a <span class="hljs-keyword">class</span>=<span class="hljs-string">"nav-link text-dark"</span> asp-area=<span class="hljs-string">""</span> asp-controller=<span class="hljs-string">"Restaurant"</span> asp-action=<span class="hljs-string">"Index"</span>&gt;Restaurants&lt;/a&gt;
        &lt;/li&gt;
        &lt;li <span class="hljs-keyword">class</span>=<span class="hljs-string">"nav-item"</span>&gt;
            &lt;a <span class="hljs-keyword">class</span>=<span class="hljs-string">"nav-link text-dark"</span> asp-area=<span class="hljs-string">""</span> asp-controller=<span class="hljs-string">"Reservation"</span> asp-action=<span class="hljs-string">"Index"</span>&gt;Reservations&lt;/a&gt;
        &lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;
</code></pre>
<h2 id="heading-testing-our-application">Testing our application</h2>
<p>We now have a functioning application that uses the new MongoDB Provider for EF Core. Now is the time to test it all and visit our endpoints to make sure it all works.</p>
<p>In the terminal run the following command:</p>
<p><code>dotnet run</code></p>
<p>Try editing restaurants and adding reservations. You can then navigate to the MongoDB Atlas database page and see that your changes are reflected in the database.</p>
<h1 id="heading-advanced-mongodb-operations-atlas-search-and-vector-search">Advanced MongoDB Operations: Atlas Search and Vector Search</h1>
<p>The EF Core provider is built on top of the MongoDB C# Driver. Since we already have access to the the MongoClient when creating the DbContext, this allows us to perform advanced MongoDB operations such as Atlas Search and Vector Search. These features enhance your application's capabilities by enabling powerful search functionalities while still leveraging the familiar EF Core framework.</p>
<h4 id="heading-atlas-search">Atlas Search</h4>
<p>Atlas Search is a full-text search engine provided by MongoDB Atlas. It allows you to run sophisticated search queries on your MongoDB data. With Atlas Search, you can implement features like autocomplete, faceted search, and relevance-based sorting.</p>
<p>To use Atlas Search with the EF Core Provider, follow these steps:</p>
<ol>
<li><p><strong>Setup Indexes in MongoDB Atlas</strong>:</p>
<ul>
<li><p>Go to your MongoDB Atlas cluster.</p>
</li>
<li><p>Navigate to the "Search" tab and create a new index on your collection. Define the fields you want to make searchable.</p>
</li>
</ul>
</li>
<li><p><strong>Define Searchable Fields in Your Models</strong>: In your C# models, ensure that the fields you want to search are properly defined. Here is an example of the definition of a Product model.</p>
<pre><code class="lang-csharp"> <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Product</span>
 {
     <span class="hljs-keyword">public</span> ObjectId Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Description { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">decimal</span> Price { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
     <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Category { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 }
</code></pre>
</li>
<li><p><strong>Performing Search Queries</strong>: Use the MongoDB .NET Driver's capabilities to perform text searches. Since EF Core itself does not directly support the MongoDB-specific search syntax, you will need to use the driver in conjunction with EF Core. Here’s an example:</p>
<pre><code class="lang-csharp"> <span class="hljs-keyword">using</span> MongoDB.Driver;
 <span class="hljs-keyword">using</span> MongoDB.Driver.Linq;

 <span class="hljs-keyword">var</span> client = <span class="hljs-keyword">new</span> MongoClient(<span class="hljs-string">"your-mongodb-connection-string"</span>);
 <span class="hljs-keyword">var</span> database = client.GetDatabase(<span class="hljs-string">"your-database-name"</span>);
 <span class="hljs-keyword">var</span> collection = database.GetCollection&lt;Product&gt;(<span class="hljs-string">"Products"</span>);

 <span class="hljs-keyword">var</span> searchResult = collection.Aggregate()
     .Match(Builders&lt;Product&gt;.Filter.Text(<span class="hljs-string">"search term"</span>))
     .ToList();
</code></pre>
</li>
</ol>
<p>This example shows how to perform a text search on the <code>Products</code> collection. The <code>Text</code> filter helps search across all indexed fields defined in your Atlas Search index.</p>
<h4 id="heading-vector-search">Vector Search</h4>
<p>Vector Search in MongoDB is used for searching documents based on vector similarities, which is particularly useful for applications involving machine learning, recommendations, and natural language processing. Vector Search allows you to query documents using vectors representing text, images, or other high-dimensional data.</p>
<ol>
<li><p><strong>Create and Store Vectors</strong>: First, ensure that your documents contain vectors. You might need to preprocess your data to generate these vectors using machine learning models.</p>
</li>
<li><p><strong>Index Vectors in MongoDB Atlas</strong>: Create a special index on the vector field in MongoDB Atlas to enable efficient vector similarity searches.</p>
</li>
<li><p><strong>Performing Vector Searches</strong>: Use the MongoDB .NET Driver to query based on vector similarity.</p>
</li>
</ol>
<h4 id="heading-integrating-with-ef-core">Integrating with EF Core</h4>
<p>While the MongoDB EF Core Provider simplifies CRUD operations, some advanced features like Atlas Search and Vector Search require direct use of the MongoDB .NET Driver. However, you can still integrate these operations within your EF Core-based application by using the driver for search functionalities and EF Core for other data management tasks.</p>
<p>By combining EF Core and MongoDB's advanced features, you can build powerful and flexible applications that leverage the best of both worlds—structured data access patterns of EF Core and the powerful search capabilities of MongoDB Atlas.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ PHP Arrays in Practice: How to Rebuild the Football Team Cards Project with PHP and MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ This is the second part of my PHP array handbook. You can find the first part here, where I cover array basics. In the first part, you learned about arrays, how to create arrays, array functions, and how to loop through arrays. This second part will ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/php-arrays-how-to-rebuild-the-football-team-cards-with-php-and-mongodb/</link>
                <guid isPermaLink="false">66adf1bf007ea266ef6d923b</guid>
                
                    <category>
                        <![CDATA[ arrays ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kolade Chris ]]>
                </dc:creator>
                <pubDate>Tue, 18 Jun 2024 20:58:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/PHP-Arrays-in-Practice-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This is the second part of my PHP array handbook. You can <a target="_blank" href="https://www.freecodecamp.org/news/php-array-handbook/">find the first part here</a>, where I cover array basics.</p>
<p>In the first part, you learned about arrays, how to create arrays, array functions, and how to loop through arrays.</p>
<p>This second part will teach you how to use PHP and MongoDB to rebuild the football team cards project of freeCodeCamp's updated JavaScript curriculum.</p>
<p>The football team data will live in a MongDB Atlas database. We will fetch it as an array, and display it based on the players selected (goalkeepers, defenders, midfielders, and forwards).</p>
<p>This will help you build on top of what you learned about looping through arrays. After all, on many occassions, you'll be looping through what you get from a database or an API, not necessarily some hard-coded arrays.</p>
<p>In order not to shock you by jumping straight into databases from arrays, we'll start with what data and databases are, and then go on to learn about:</p>
<ul>
<li><p>Relational vs non-relational databases</p>
</li>
<li><p>How to use MongoDB Atlas</p>
</li>
<li><p>How to Install MongoDB for PHP on a Mac</p>
</li>
<li><p>How to set up MongoDB Atlas</p>
</li>
<li><p>How to build a CRUD app with PHP and MongoDB Atlas</p>
</li>
<li><p>And finally, how to rebuild the football team cards project with PHP and MongoDB Atlas</p>
</li>
</ul>
<h2 id="heading-pre-requisites">Pre-requisites</h2>
<p>To get the best put of this guide, I suggest you have a basic knowledge of the following:</p>
<ul>
<li><p>PHP fundamentals (variables, arrays, functions, loops)</p>
</li>
<li><p>HTML and CSS</p>
</li>
<li><p>JavaScript events</p>
</li>
<li><p>Command line</p>
</li>
<li><p>Composer</p>
</li>
<li><p>How to set up a PHP development environment with VS Code</p>
</li>
<li><p>Databases</p>
</li>
<li><p>MongoDB Atlas</p>
</li>
<li><p>Git and GitHub</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-are-data-and-databases">What are Data and Databases?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-relational-vs-non-relational-databases">Relational vs Non-relational Databases</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-mongodb-atlas-an-example-of-a-non-relational-database">MongoDB Atlas – An Example of a Non-relational Database</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-install-mongodb-for-php">How to Install MongoDB for PHP</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-install-the-mongodb-extension-with-pecl-php-extension-community-library">Step 1: Install the MongoDB Extension with PECL (PHP Extension Community Library)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-modify-the-phpini-file-to-include-the-mongodb-extension">Step 2: Modify the <code>php.ini</code> File to Include the MongoDB Extension</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-verify-the-installation-of-the-mongodb-extension">Step 3: Verify the Installation of the MongoDB Extension</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-set-up-a-mongodb-atlas-cluster">Step 4: Set Up a MongoDB Atlas Cluster</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-install-the-mongodb-php-library">Step 5: Install the MongoDB PHP Library</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-crud-operations-using-php-and-mongodb">CRUD Operations Using PHP and MongoDB</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-install-mongodb-library-and-dotenv-package">Step 1: Install MongoDB Library and Dotenv Package</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-create-a-env-file-for-your-mongodb-atlas-uri-credential">Step 2: Create a <code>.env</code> File for your MongoDB Atlas URI Credential</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-create-a-database-connection-file">Step 3: Create a Database Connection File</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-the-read-part-of-the-crud">Step 4: The <code>READ</code> Part of the CRUD</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-the-create-part-of-the-crud">Step 5: The <code>CREATE</code> Part of the CRUD</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-the-update-part-of-the-crud">Step 6: The <code>UPDATE</code> Part of the CRUD</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-7-the-delete-part-of-the-crud">Step 7: The <code>DELETE</code> Part of the CRUD</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-project-how-to-use-php-to-rebuild-the-football-team-cards-project-of-the-updated-javascript-curriculum">Project: How to Use PHP to Rebuild the Football Team Cards Project of the Updated JavaScript Curriculum</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-set-up-mongodb-atlas">Step 1: Set up MongoDB Atlas</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-install-the-project-dependencies-with-composer">Step 2: Install the Project Dependencies with Composer</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-create-project-files">Step 3: Create Project Files</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-wrap-the-select-tag-in-a-form-element">Step 4: Wrap the <code>select</code> tag in a <code>form</code> Element</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-create-the-logic-for-fetching-the-footballers-from-the-footballers-collection">Step 5: Create the Logic for Fetching the Footballers from the <code>footballers</code> Collection</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-create-the-logic-for-filtering-the-footballers-based-on-position">Step 6: Create the Logic for Filtering the Footballers Based on Position</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-7-display-the-players-on-the-page-based-on-the-selected-position">Step 7: Display the Players on the Page Based on the Selected Position</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h2 id="heading-what-are-data-and-databases">What are Data and Databases?</h2>
<p>Data is central to pretty much everything in the modern world. The people you see on social media and other websites, the content they post, the comments they add to posts, and many other online activities all produce a lot of data. Even patient files in a hospital or a company's payroll hosted on a local server are data. Data does not have to be on the Internet.</p>
<p>To effectively manage and utilize data for growth, you need a <strong>database</strong>. A <strong>Database</strong> is a structured collection of data that helps you efficiently store, retrieve, and manipulate that data.</p>
<p>Databases come in two primary types – relational and non-relational databases. We'll discuss the differences between them next.</p>
<p>Both relational and non-relational databases are managed with what is called database management systems (DBMS). A DBMS is an interface between the user and the database that allows you to create, read, update, and delete data in the database.</p>
<h2 id="heading-relational-vs-non-relational-databases">Relational vs Non-relational Databases</h2>
<h3 id="heading-what-are-relational-databases">What are Relational Databases?</h3>
<p><strong>Relational databases</strong> organize data into tables consisting of rows and columns. Each table represents a specific entity, such as customers or products. The columns define the attributes of these entities, like the customer name or product name.</p>
<p>The relational model uses structured query language (SQL) for querying and managing data. Relationships between tables are established through primary and foreign keys to ensure data integrity and reduce redundancy.</p>
<p>Relational databases are known for their robustness, consistency, and support for complex queries. They are well-suited for applications that require multi-row transactions, such as financial systems, enterprise resource planning (ERP) software, and customer relationship management (CRM) systems.</p>
<p>Examples of relational databases are MySQL, PostgreSQL, and Microsoft SQL Server.</p>
<h3 id="heading-what-are-non-relational-databases">What are Non-Relational Databases?</h3>
<p><strong>Non-relational</strong> databases store and manage data in flexible, schema-less formats like key-value pairs, documents, wide-columns, or graphs. They are also known as NoSQL databases because they don't use SQL like relational databases.</p>
<p>Non-relational databases are designed to scale horizontally, making them ideal for large-scale data processing and real-time web applications.</p>
<p>Non-relational databases are easy to use, scalable, and high-performing at the same time. Due to that, they often sacrifice some degree of consistency in favor of availability and partition tolerance.</p>
<p>Common use cases include real-time analytics, real-time web apps, and applications requiring high-speed data ingestion.</p>
<h3 id="heading-mongodb-atlas-an-example-of-a-non-relational-database">MongoDB Atlas – An Example of a Non-relational Database</h3>
<p>MongoDB Atlas is a non-relational database that stores data in a document-oriented JSON-like format called BSON (Binary JSON). BSON extends the JSON model to provide additional data types and to be efficient for encoding and decoding within various programming languages.</p>
<p>MongoDB Atlas offers the flexibility and scalability of MongoDB, with the benefits of automated deployment, backups, and monitoring. It allows developers to focus on building applications without bothering about database management</p>
<p>MongoDB Atlas also supports advanced features such as data partitioning, replication, and global distribution. This makes it a powerful choice for modern applications requiring flexibility and performance.</p>
<h2 id="heading-how-to-install-mongodb-for-php">How to Install MongoDB for PHP</h2>
<p>Before you can install MongoDB for PHP, make sure you have PHP itself installed correctly.</p>
<p>On a Mac, you can install PHP with homebrew by running <code>brew install PHP</code>. In addition to that, make sure you have Apache installed by running <code>brew install httpd</code> and starting it by running <code>brew services start httpd</code>.</p>
<p>You can follow the steps below to install MongoDB for PHP on a Mac.</p>
<h3 id="heading-step-1-install-the-mongodb-extension-with-pecl-php-extension-community-library">Step 1: Install the MongoDB Extension with PECL (PHP Extension Community Library)</h3>
<p>Install the MongoDB extension for PHP by running <code>pecl install mongodb</code>.</p>
<h3 id="heading-step-2-modify-the-phpini-file-to-include-the-mongodb-extension">Step 2: Modify the <code>php.ini</code> File to Include the MongoDB Extension</h3>
<p>Installing the MongoDB extension should automatically add the necessary configurations to the <code>php.ini</code> file. But of it doesnt do that, locate the <code>php.ini</code> file by running the command below:</p>
<pre><code class="lang-bash">$ php --ini
Configuration File (php.ini) Path: /usr/<span class="hljs-built_in">local</span>/etc/php/8.3
</code></pre>
<p>After that, paste the following at the end of the <code>php.ini</code> file and save it:</p>
<pre><code class="lang-bash">extension=mongodb.so
</code></pre>
<p>After doing that, restart Apache by running <code>brew services restart httpd</code>.</p>
<h3 id="heading-step-3-verify-the-installation-of-the-mongodb-extension">Step 3: Verify the Installation of the MongoDB Extension</h3>
<p>Run the command below to see whether the PHP extension has been successflly installed:</p>
<pre><code class="lang-bash">php -i | grep mongo
</code></pre>
<p>You should see something like this in the terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-09.21.50.png" alt="Screenshot-2024-05-24-at-09.21.50" width="600" height="400" loading="lazy"></p>
<p>Check out <a target="_blank" href="https://www.mongodb.com/docs/languages/php/">the MongoDB PHP docs</a> for more information on how to use MongoDB with PHP and frameworks like Laravel and Symfony.</p>
<h3 id="heading-step-4-set-up-a-mongodb-atlas-cluster">Step 4: Set Up a MongoDB Atlas Cluster</h3>
<p>To test out the PHP extension you just installed, you need a MongoDB database. Atlas makes this easy for you because the heavy lifting is handled on the cloud.</p>
<h4 id="heading-1-login-to-your-mongodb-account">1. Login to your MongoDB Account</h4>
<p>Head over to https://cloud.mongodb.com/ and log in to your account. If you don't have an account, <strong>you can create one for free</strong>.</p>
<h4 id="heading-2-create-a-project">2. Create a Project</h4>
<p>If you have existing projects, create a new project by clicking on the arrow right beside the currently opened project and selecting "New Project".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-09.34.05.png" alt="Screenshot-2024-05-24-at-09.34.05" width="600" height="400" loading="lazy"></p>
<p>Give your project a name and click the "Next" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-09.37.13.png" alt="Screenshot-2024-05-24-at-09.37.13" width="600" height="400" loading="lazy"></p>
<p>Click "Create Project" to finally create the project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-09.38.29.png" alt="Screenshot-2024-05-24-at-09.38.29" width="600" height="400" loading="lazy"></p>
<h4 id="heading-3-create-a-cluster">3. Create a Cluster</h4>
<p>After creating a project, you should be prompted to create a cluster. If you're not, make sure you're in the Overview tab. From there, click the big "Create" button:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/create-giant-1.png" alt="create-giant-1" width="600" height="400" loading="lazy"></p>
<p>Select the "MO" free tier, give your cluster a name, and click the "Create Deployment" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-09.44.11.png" alt="Screenshot-2024-05-24-at-09.44.11" width="600" height="400" loading="lazy"></p>
<p>I have given the cluster the name <code>movie-list</code>.</p>
<p>Just keep in mind that as your database grows, you might need to upgrade to one of the paid tiers.</p>
<h4 id="heading-4-create-a-database-user">4. Create a Database User</h4>
<p>Immediately after you create your cluster, you'll be prompted to create a database user. Fill in your database user username and password and click the "Create Database User" button. Then click "Choose a connection method".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-09.50.54.png" alt="Screenshot-2024-05-24-at-09.50.54" width="600" height="400" loading="lazy"></p>
<p>Make sure you enter a password you can remember or save it in a password manager.</p>
<h4 id="heading-5-choose-a-connection-method">5. Choose a Connection Method</h4>
<p>You'll see several methods you can use to connect to the cluster once you click the "Choose a connection method" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-09.56.37.png" alt="Screenshot-2024-05-24-at-09.56.37" width="600" height="400" loading="lazy"></p>
<p>Select Drivers from the list.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-09.58.02.png" alt="Screenshot-2024-05-24-at-09.58.02" width="600" height="400" loading="lazy"></p>
<p>Choose PHP from the list and select PHP Lib 1.9 + MongoDB 1.10 or later as the version to use. Then copy the connection string and click the "Done" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-10.02.55.png" alt="Screenshot-2024-05-24-at-10.02.55" width="600" height="400" loading="lazy"></p>
<h4 id="heading-6-choose-network-access">6. Choose Network Access</h4>
<p>Head over to the "Network Access" tab and select "Add IP ADDRESS", click "ALLOW ACCESS FROM ANYWHERE", and then click the "Confirm" button. You can change this later depending on where your app is deployed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-10.05.03.png" alt="Screenshot-2024-05-24-at-10.05.03" width="600" height="400" loading="lazy"></p>
<p>Go back to the "Database" tab and click the "Browse Collections" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-10.07.48.png" alt="Screenshot-2024-05-24-at-10.07.48" width="600" height="400" loading="lazy"></p>
<p>Select "Load a Sample Dataset" so you don't have to add your own data – at least for now.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-10.24.54.png" alt="Screenshot-2024-05-24-at-10.24.54" width="600" height="400" loading="lazy"></p>
<p>Now you should see the following databases:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-10.28.04.png" alt="Screenshot-2024-05-24-at-10.28.04" width="600" height="400" loading="lazy"></p>
<p>To test that your MongoDB extension for PHP is running, you can query any of the data in those databases. But first, you need to install the MongoDB PHP library with <code>composer</code>. <code>composer</code> lets you manage dependencies for your PHP project.</p>
<h3 id="heading-step-5-install-the-mongodb-php-library">Step 5: Install the MongoDB PHP Library</h3>
<p>If you don't have <code>composer</code> installed, install it with homebrew by running <code>brew install composer</code>.</p>
<p>After that, create a folder and open it with your Text Editor. If your Text Editor has an integrated terminal, open it and run the command below:</p>
<pre><code class="lang-bash">composer require mongodb/mongodb
</code></pre>
<p>If the installation is successful, you'll see a <code>vendor</code> folder, along with <code>composer.json</code> and <code>composer.lock</code> files in the root of your project. You'll also see the following in the terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-10.36.29.png" alt="Screenshot-2024-05-24-at-10.36.29" width="600" height="400" loading="lazy"></p>
<p>Now you need to query any data in your atlas database and display them.</p>
<p>Create an <code>index.php</code> file and paste the following inside it:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;

<span class="hljs-comment">// Your connection string</span>
$client = <span class="hljs-keyword">new</span> MongoDB\Client(
 <span class="hljs-string">'mongodb+srv://username:&lt;password&gt;@movie-list.s6r7qkr.mongodb.net/?retryWrites=true&amp;w=majority&amp;appName=movie-list'</span>
);

$movies = $client-&gt;selectCollection(<span class="hljs-string">'sample_mflix'</span>, <span class="hljs-string">'movies'</span>);
$document = $movies-&gt;findOne([<span class="hljs-string">'title'</span> =&gt; <span class="hljs-string">'Wild and Woolly'</span>]);

<span class="hljs-keyword">echo</span> <span class="hljs-string">'&lt;pre&gt;'</span>;
print_r($document);
</code></pre>
<p>The code above lets you connect to the <code>movies</code> database in the <code>sample_mflix</code> collection with the <code>selectCollection()</code> function and query a movie titled "Wild and Bolly" in it.</p>
<p><strong>Note</strong>: Make sure you replace the existing connection string with your own. You copied this in item 5 of step 4. Also, make sure you replace <code>&lt;password&gt;</code> with your database user password.</p>
<p>After that, run your PHP app (with <code>php -S localhost:8000</code> on Mac in the terminal). If you have everything set up correctly, you should see the following in the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-05-24-at-10.54.05.png" alt="Screenshot-2024-05-24-at-10.54.05" width="600" height="400" loading="lazy"></p>
<p><strong>Note</strong>: I have the data formatted nicely because I installed the PHP View Chrome extension. It prints everything you have inside the <code>print_r()</code> function like that.</p>
<h2 id="heading-crud-operations-using-php-and-mongodb">CRUD Operations Using PHP and MongoDB</h2>
<p>With MongoDB Atlas for database management and UI persistence, and PHP for server-side logic, you can build an application that implements full CRUD operations – create, read, update, and delete.</p>
<p>The particular CRUD app we are building is a movie list. So make sure you set up an Atlas database for it, as we already covered in this guide.</p>
<p>Now let's look at how you can build a movie list CRUD app.</p>
<h3 id="heading-step-1-install-mongodb-library-and-dotenv-package">Step 1: Install MongoDB Library and Dotenv Package</h3>
<p>Make sure you have a MongoDB extension and a Dotenv package to help manage your <code>.env</code> variables by running the following commands:</p>
<pre><code class="lang-bash">composer require mongodb/mongodb
composer require vlucas/phpdotenv
</code></pre>
<h3 id="heading-step-2-create-a-env-file-for-your-mongodb-atlas-uri-credential">Step 2: Create a <code>.env</code> File for your MongoDB Atlas URI Credential</h3>
<p>Create a <code>.env</code> file and add the following in it:</p>
<pre><code class="lang-md">MDB<span class="hljs-emphasis">_URI="Your MongoDB Atlas connection string"</span>
</code></pre>
<h3 id="heading-step-3-create-a-database-connection-file">Step 3: Create a Database Connection File</h3>
<p>Create a <code>mongo_atlas_setup.php</code> file for the database connection in the root and paste the following in it:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;

$dotenv = Dotenv\Dotenv::createImmutable(<span class="hljs-keyword">__DIR__</span>);
$dotenv-&gt;load();

$client = <span class="hljs-keyword">new</span> MongoDB\Client($_ENV[<span class="hljs-string">'MDB_URI'</span>]);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMongoClient</span>(<span class="hljs-params"></span>)
</span>{
 <span class="hljs-keyword">global</span> $client;
 <span class="hljs-keyword">return</span> $client;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMongoCollection</span>(<span class="hljs-params">$database, $collection</span>)
</span>{
 $client = getMongoClient();
 <span class="hljs-keyword">return</span> $client-&gt;selectCollection($database, $collection);
}
</code></pre>
<p>With the code above, we are:</p>
<ul>
<li><p>loading the dependencies required for the project</p>
</li>
<li><p>loading the environment variable</p>
</li>
<li><p>using a function to get the database and the collection we want within it</p>
</li>
</ul>
<p>Importing the file and calling the <code>getMongoCollection</code> in it with the database and the collection in it will let you connect to the database and the collection.</p>
<h3 id="heading-step-4-the-read-part-of-the-crud">Step 4: The <code>READ</code> Part of the CRUD</h3>
<p>In the root again, create an <code>index.php</code> file that will take care of the READ part of the CRUD. Paste the following in the file:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/mongo_atlas_setup.php'</span>;

$movies_list = getMongoCollection(<span class="hljs-string">'movie_list'</span>, <span class="hljs-string">'movies'</span>);
$movies = $movies_list-&gt;find([], [<span class="hljs-string">'sort'</span> =&gt; [<span class="hljs-string">'_id'</span> =&gt; <span class="hljs-number">-1</span>]]);
<span class="hljs-meta">?&gt;</span>

&lt;!DOCTYPE html&gt;
&lt;html lang=<span class="hljs-string">"en"</span>&gt;

&lt;head&gt;
 &lt;meta charset=<span class="hljs-string">"UTF-8"</span>&gt;
 &lt;meta name=<span class="hljs-string">"viewport"</span> content=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;
 &lt;title&gt;Movie <span class="hljs-keyword">List</span> CRUD App&lt;/title&gt;
 &lt;script src=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>&gt;&lt;/script&gt;
&lt;/head&gt;

&lt;body <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">bg</span>-<span class="hljs-title">gray</span>-100 <span class="hljs-title">p</span>-10"&gt;

 &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">max</span>-<span class="hljs-title">w</span>-4<span class="hljs-title">xl</span> <span class="hljs-title">mx</span>-<span class="hljs-title">auto</span> <span class="hljs-title">bg</span>-<span class="hljs-title">white</span> <span class="hljs-title">p</span>-6 <span class="hljs-title">rounded</span> <span class="hljs-title">shadow</span>"&gt;
   &lt;<span class="hljs-title">h1</span> <span class="hljs-title">class</span>="<span class="hljs-title">text</span>-3<span class="hljs-title">xl</span> <span class="hljs-title">font</span>-<span class="hljs-title">bold</span> <span class="hljs-title">mb</span>-4 <span class="hljs-title">text</span>-<span class="hljs-title">center</span>"&gt;<span class="hljs-title">Movie</span> <span class="hljs-title">List</span> <span class="hljs-title">CRUD</span> <span class="hljs-title">App</span>&lt;/<span class="hljs-title">h1</span>&gt;

   &lt;?<span class="hljs-title">php</span> <span class="hljs-title">include</span> '<span class="hljs-title">create</span>.<span class="hljs-title">php</span>' ?&gt;

   &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">space</span>-<span class="hljs-title">y</span>-4"&gt;
     &lt;?<span class="hljs-title">php</span> <span class="hljs-title">foreach</span> ($<span class="hljs-title">movies</span> <span class="hljs-title">as</span> $<span class="hljs-title">movie</span>) : ?&gt;
       &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">p</span>-4 <span class="hljs-title">border</span> <span class="hljs-title">rounded</span> <span class="hljs-title">shadow</span>-<span class="hljs-title">sm</span> <span class="hljs-title">bg</span>-<span class="hljs-title">gray</span>-50"&gt;
         &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">text</span>-2<span class="hljs-title">xl</span> <span class="hljs-title">font</span>-<span class="hljs-title">semibold</span>"&gt;&lt;?= $<span class="hljs-title">movie</span>['<span class="hljs-title">movie_title</span>'] ?&gt;&lt;/<span class="hljs-title">h2</span>&gt;
         &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">text</span>-<span class="hljs-title">gray</span>-700"&gt;<span class="hljs-title">Year</span>: &lt;?= $<span class="hljs-title">movie</span>['<span class="hljs-title">movie_year</span>'] ?&gt;&lt;/<span class="hljs-title">p</span>&gt;
         &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">mt</span>-2"&gt;
           &lt;<span class="hljs-title">a</span> <span class="hljs-title">href</span>="<span class="hljs-title">update</span>.<span class="hljs-title">php</span>?<span class="hljs-title">id</span>=&lt;?= $<span class="hljs-title">movie</span>['<span class="hljs-title">_id</span>'] ?&gt;" <span class="hljs-title">class</span>="<span class="hljs-title">bg</span>-<span class="hljs-title">yellow</span>-500 <span class="hljs-title">text</span>-<span class="hljs-title">white</span> <span class="hljs-title">py</span>-1 <span class="hljs-title">px</span>-3 <span class="hljs-title">rounded</span>"&gt;<span class="hljs-title">Update</span>&lt;/<span class="hljs-title">a</span>&gt;
           &lt;<span class="hljs-title">a</span> <span class="hljs-title">href</span>="<span class="hljs-title">delete</span>.<span class="hljs-title">php</span>?<span class="hljs-title">id</span>=&lt;?= $<span class="hljs-title">movie</span>['<span class="hljs-title">_id</span>'] ?&gt;" <span class="hljs-title">onclick</span>="<span class="hljs-title">return</span> <span class="hljs-title">confirm</span>('<span class="hljs-title">Are</span> <span class="hljs-title">you</span> <span class="hljs-title">sure</span> <span class="hljs-title">you</span> <span class="hljs-title">want</span> <span class="hljs-title">to</span> <span class="hljs-title">delete</span> <span class="hljs-title">this</span> <span class="hljs-title">movie</span>?')" <span class="hljs-title">class</span>="<span class="hljs-title">bg</span>-<span class="hljs-title">red</span>-500 <span class="hljs-title">text</span>-<span class="hljs-title">white</span> <span class="hljs-title">py</span>-1 <span class="hljs-title">px</span>-3 <span class="hljs-title">rounded</span>"&gt;<span class="hljs-title">Delete</span>&lt;/<span class="hljs-title">a</span>&gt;
         &lt;/<span class="hljs-title">div</span>&gt;
       &lt;/<span class="hljs-title">div</span>&gt;
     &lt;?<span class="hljs-title">php</span> <span class="hljs-title">endforeach</span> ?&gt;
   &lt;/<span class="hljs-title">div</span>&gt;
 &lt;/<span class="hljs-title">div</span>&gt;

&lt;/<span class="hljs-title">body</span>&gt;

&lt;/<span class="hljs-title">html</span>&gt;</span>
</code></pre>
<p>Notice that there are the Update and Delete linking to an <code>update.php</code> and a <code>delete.php</code> files with the id of the movie clicked. That way, we will know which movie is clicked in order to update or delete it. There's also an include statement for a <code>create.php</code> file.</p>
<p>For now, you can go ahead and create the <code>create.php</code>, <code>update.php</code>, and <code>delete.php</code> files in the root.</p>
<p>At this point, you won't see anything in the UI yet because you need to handle the creation functionality.</p>
<h3 id="heading-step-5-the-create-part-of-the-crud">Step 5: The <code>CREATE</code> Part of the CRUD</h3>
<p>Create a <code>create.php</code> file in the root (if you haven't already) and paste in the following:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/mongo_atlas_setup.php'</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] === <span class="hljs-string">'POST'</span>) {
 $movies = getMongoCollection(<span class="hljs-string">'movie_list'</span>, <span class="hljs-string">'movies'</span>);
 $newMovie = [
   <span class="hljs-string">'movie_title'</span> =&gt; $_POST[<span class="hljs-string">'movie-title'</span>],
   <span class="hljs-string">'movie_year'</span> =&gt; (<span class="hljs-keyword">int</span>)$_POST[<span class="hljs-string">'movie-year'</span>],
 ];
 $result = $movies-&gt;insertOne($newMovie);
 <span class="hljs-keyword">if</span> ($result-&gt;getInsertedCount() === <span class="hljs-number">1</span>) {
   <span class="hljs-comment">// echo "Movie created successfully!";</span>
   header(<span class="hljs-string">'Location: '</span> . <span class="hljs-string">'/'</span>);
 } <span class="hljs-keyword">else</span> {
   <span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed to create movie"</span>;
 }
}
<span class="hljs-meta">?&gt;</span>

&lt;form method=<span class="hljs-string">"POST"</span> action=<span class="hljs-string">"create.php"</span> <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">space</span>-<span class="hljs-title">y</span>-4 <span class="hljs-title">mb</span>-6"&gt;
 &lt;<span class="hljs-title">div</span>&gt;
   &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">block</span> <span class="hljs-title">text</span>-<span class="hljs-title">gray</span>-700"&gt;<span class="hljs-title">Movie</span> <span class="hljs-title">Title</span>&lt;/<span class="hljs-title">label</span>&gt;
   &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">name</span>="<span class="hljs-title">movie</span>-<span class="hljs-title">title</span>" <span class="hljs-title">required</span> <span class="hljs-title">class</span>="<span class="hljs-title">w</span>-<span class="hljs-title">full</span> <span class="hljs-title">p</span>-2 <span class="hljs-title">border</span> <span class="hljs-title">rounded</span> <span class="hljs-title">max</span>-<span class="hljs-title">w</span>-<span class="hljs-title">md</span>"&gt;
 &lt;/<span class="hljs-title">div</span>&gt;
 &lt;<span class="hljs-title">div</span>&gt;
   &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">block</span> <span class="hljs-title">text</span>-<span class="hljs-title">gray</span>-700"&gt;<span class="hljs-title">Movie</span> <span class="hljs-title">Year</span>&lt;/<span class="hljs-title">label</span>&gt;
   &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">name</span>="<span class="hljs-title">movie</span>-<span class="hljs-title">year</span>" <span class="hljs-title">required</span> <span class="hljs-title">class</span>="<span class="hljs-title">w</span>-<span class="hljs-title">full</span> <span class="hljs-title">p</span>-2 <span class="hljs-title">border</span> <span class="hljs-title">rounded</span> <span class="hljs-title">max</span>-<span class="hljs-title">w</span>-<span class="hljs-title">md</span>"&gt;
 &lt;/<span class="hljs-title">div</span>&gt;
 &lt;<span class="hljs-title">button</span> <span class="hljs-title">type</span>="<span class="hljs-title">submit</span>" <span class="hljs-title">class</span>="<span class="hljs-title">bg</span>-<span class="hljs-title">green</span>-500 <span class="hljs-title">text</span>-<span class="hljs-title">white</span> <span class="hljs-title">py</span>-2 <span class="hljs-title">px</span>-4 <span class="hljs-title">rounded</span>"&gt;<span class="hljs-title">Create</span>&lt;/<span class="hljs-title">button</span>&gt;
&lt;/<span class="hljs-title">form</span>&gt;</span>
</code></pre>
<p>The code above contains the form and input elements for creating a movie. We are then using the name attributes in those input elements to create the <code>POST</code> request that will let us create a movie and save it in the <code>movies</code> collection of a <code>movie_list</code> database.</p>
<h3 id="heading-step-6-the-update-part-of-the-crud">Step 6: The <code>UPDATE</code> Part of the CRUD</h3>
<p>To handle the updating, we need to create a separate file and do something similar to how the movie creation worked. The exeception is that we are going to use the id (<code>_id</code>) field to determine whether the movie exists and then update it instead of creating a fresh one.</p>
<p>To do that, create an <code>update.php</code> file (if you haven't already) in the root and paste in the following:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/mongo_atlas_setup.php'</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">MongoDB</span>\<span class="hljs-title">BSON</span>\<span class="hljs-title">ObjectId</span>;

$movies_list = getMongoCollection(<span class="hljs-string">'movie_list'</span>, <span class="hljs-string">'movies'</span>);
$title = <span class="hljs-string">''</span>;
$year = <span class="hljs-string">''</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] === <span class="hljs-string">'POST'</span>) {
 $filter = [<span class="hljs-string">'_id'</span> =&gt; <span class="hljs-keyword">new</span> ObjectId($_POST[<span class="hljs-string">'id'</span>])];

 $update = [<span class="hljs-string">'$set'</span> =&gt; [
   <span class="hljs-string">'movie_title'</span> =&gt; $_POST[<span class="hljs-string">'movie-title'</span>],
   <span class="hljs-string">'movie_year'</span> =&gt; (<span class="hljs-keyword">int</span>)$_POST[<span class="hljs-string">'movie-year'</span>],
 ]];

 $result = $movies_list-&gt;updateOne($filter, $update);

 <span class="hljs-keyword">if</span> ($result-&gt;getModifiedCount() === <span class="hljs-number">1</span>) {
   <span class="hljs-comment">// echo "Movie updated successfully!";</span>
   header(<span class="hljs-string">'Location: '</span> . <span class="hljs-string">'/'</span>);
 } <span class="hljs-keyword">else</span> {
   <span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed to update movie."</span>;
 }
} <span class="hljs-keyword">else</span> {
 <span class="hljs-keyword">if</span> (<span class="hljs-keyword">isset</span>($_GET[<span class="hljs-string">'id'</span>])) {
   $id = $_GET[<span class="hljs-string">'id'</span>];
   $movie = $movies_list-&gt;findOne([<span class="hljs-string">'_id'</span> =&gt; <span class="hljs-keyword">new</span> ObjectId($id)]);
   <span class="hljs-keyword">if</span> ($movie) {
     $title = $movie[<span class="hljs-string">'movie_title'</span>];
     $year = $movie[<span class="hljs-string">'movie_year'</span>];
   } <span class="hljs-keyword">else</span> {
     <span class="hljs-keyword">echo</span> <span class="hljs-string">"Movie not found."</span>;
     <span class="hljs-keyword">exit</span>;
   }
 } <span class="hljs-keyword">else</span> {
   <span class="hljs-keyword">echo</span> <span class="hljs-string">"No movie ID provided."</span>;
   <span class="hljs-keyword">exit</span>;
 }
}
<span class="hljs-meta">?&gt;</span>

&lt;!DOCTYPE html&gt;
&lt;html lang=<span class="hljs-string">"en"</span>&gt;

&lt;head&gt;
 &lt;meta charset=<span class="hljs-string">"UTF-8"</span>&gt;
 &lt;meta name=<span class="hljs-string">"viewport"</span> content=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;
 &lt;script src=<span class="hljs-string">"https://cdn.tailwindcss.com"</span>&gt;&lt;/script&gt;
 &lt;title&gt;Update Movie &lt;/title&gt;
&lt;/head&gt;

&lt;body <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">bg</span>-<span class="hljs-title">gray</span>-100 <span class="hljs-title">p</span>-10"&gt;

 &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">max</span>-<span class="hljs-title">w</span>-4<span class="hljs-title">xl</span> <span class="hljs-title">mx</span>-<span class="hljs-title">auto</span> <span class="hljs-title">bg</span>-<span class="hljs-title">white</span> <span class="hljs-title">p</span>-6 <span class="hljs-title">rounded</span> <span class="hljs-title">shadow</span>"&gt;
   &lt;<span class="hljs-title">h1</span> <span class="hljs-title">class</span>="<span class="hljs-title">text</span>-3<span class="hljs-title">xl</span> <span class="hljs-title">font</span>-<span class="hljs-title">bold</span> <span class="hljs-title">mb</span>-4"&gt;<span class="hljs-title">Update</span> &lt;?= $<span class="hljs-title">title</span> ?&gt; &lt;/<span class="hljs-title">h1</span>&gt;

   &lt;<span class="hljs-title">form</span> <span class="hljs-title">method</span>="<span class="hljs-title">POST</span>" <span class="hljs-title">action</span>="<span class="hljs-title">update</span>.<span class="hljs-title">php</span>" <span class="hljs-title">class</span>="<span class="hljs-title">space</span>-<span class="hljs-title">y</span>-4"&gt;
     &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">hidden</span>" <span class="hljs-title">name</span>="<span class="hljs-title">id</span>" <span class="hljs-title">value</span>="&lt;?<span class="hljs-title">php</span> <span class="hljs-title">echo</span> $<span class="hljs-title">id</span>; ?&gt;"&gt;

     &lt;<span class="hljs-title">div</span>&gt;
       &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">block</span> <span class="hljs-title">text</span>-<span class="hljs-title">gray</span>-700"&gt;<span class="hljs-title">Title</span>&lt;/<span class="hljs-title">label</span>&gt;
       &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">name</span>="<span class="hljs-title">movie</span>-<span class="hljs-title">title</span>" <span class="hljs-title">value</span>="&lt;?= <span class="hljs-title">htmlspecialchars</span>($<span class="hljs-title">title</span>); ?&gt;" <span class="hljs-title">required</span> <span class="hljs-title">class</span>="<span class="hljs-title">w</span>-<span class="hljs-title">full</span> <span class="hljs-title">p</span>-2 <span class="hljs-title">border</span> <span class="hljs-title">rounded</span>" /&gt;
     &lt;/<span class="hljs-title">div</span>&gt;

     &lt;<span class="hljs-title">div</span>&gt;
       &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">block</span> <span class="hljs-title">text</span>-<span class="hljs-title">gray</span>-700"&gt;<span class="hljs-title">Release</span> <span class="hljs-title">Year</span>&lt;/<span class="hljs-title">label</span>&gt;
       &lt;<span class="hljs-title">input</span> <span class="hljs-title">type</span>="<span class="hljs-title">number</span>" <span class="hljs-title">name</span>="<span class="hljs-title">movie</span>-<span class="hljs-title">year</span>" <span class="hljs-title">value</span>="&lt;?= <span class="hljs-title">htmlspecialchars</span>($<span class="hljs-title">year</span>); ?&gt;" <span class="hljs-title">required</span> <span class="hljs-title">class</span>="<span class="hljs-title">w</span>-<span class="hljs-title">full</span> <span class="hljs-title">p</span>-2 <span class="hljs-title">border</span> <span class="hljs-title">rounded</span>" /&gt;
     &lt;/<span class="hljs-title">div</span>&gt;

     &lt;<span class="hljs-title">button</span> <span class="hljs-title">class</span>=" <span class="hljs-title">bg</span>-<span class="hljs-title">green</span>-500 <span class="hljs-title">text</span>-<span class="hljs-title">white</span> <span class="hljs-title">py</span>-2 <span class="hljs-title">px</span>-4 <span class="hljs-title">rounded</span>" <span class="hljs-title">type</span>="<span class="hljs-title">submit</span>"&gt;<span class="hljs-title">Update</span>&lt;/<span class="hljs-title">button</span>&gt;
   &lt;/<span class="hljs-title">form</span>&gt;

   &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">mt</span>-4"&gt;
     &lt;<span class="hljs-title">a</span> <span class="hljs-title">href</span>="<span class="hljs-title">index</span>.<span class="hljs-title">php</span>" <span class="hljs-title">class</span>="<span class="hljs-title">bg</span>-<span class="hljs-title">gray</span>-500 <span class="hljs-title">text</span>-<span class="hljs-title">white</span> <span class="hljs-title">py</span>-2 <span class="hljs-title">px</span>-4 <span class="hljs-title">rounded</span>"&gt;<span class="hljs-title">Back</span> <span class="hljs-title">to</span> <span class="hljs-title">List</span>&lt;/<span class="hljs-title">a</span>&gt;
   &lt;/<span class="hljs-title">div</span>&gt;
 &lt;/<span class="hljs-title">div</span>&gt;

&lt;/<span class="hljs-title">body</span>&gt;

&lt;/<span class="hljs-title">html</span>&gt;</span>
</code></pre>
<h3 id="heading-step-7-the-delete-part-of-the-crud">Step 7: The <code>DELETE</code> Part of the CRUD</h3>
<p>To handle the delete functionality, we can get the movie and use the <code>deleteOne</code> function provided by MongoDB to delete it. Once the deleting is done, we will then use the <code>header()</code> function again to redirect to the home page.</p>
<p>Paste the following code in your <code>delete.php</code> file:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/mongo_atlas_setup.php'</span>;

<span class="hljs-keyword">use</span> <span class="hljs-title">MongoDB</span>\<span class="hljs-title">BSON</span>\<span class="hljs-title">ObjectId</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] === <span class="hljs-string">'GET'</span> &amp;&amp; <span class="hljs-keyword">isset</span>($_GET[<span class="hljs-string">'id'</span>])) {
 $movies = getMongoCollection(<span class="hljs-string">'movie_list'</span>, <span class="hljs-string">'movies'</span>);
 $filter = [<span class="hljs-string">'_id'</span> =&gt; <span class="hljs-keyword">new</span> ObjectId($_GET[<span class="hljs-string">'id'</span>])];
 $result = $movies-&gt;deleteOne($filter);
 <span class="hljs-keyword">if</span> ($result-&gt;getDeletedCount() === <span class="hljs-number">1</span>) {
   <span class="hljs-comment">// echo "Movie deleted successfully!";</span>
   header(<span class="hljs-string">'Location: '</span> . <span class="hljs-string">'/'</span>);
 } <span class="hljs-keyword">else</span> {
   <span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed to delete movie."</span>;
 }
} <span class="hljs-keyword">else</span> {
 <span class="hljs-keyword">echo</span> <span class="hljs-string">"No movie provided."</span>;
}
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>This is what the CRUD app should look like now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/CRUD-gif.gif" alt="CRUD-gif" width="600" height="400" loading="lazy"></p>
<p>All the code is in this <a target="_blank" href="https://github.com/Ksound22/crud-app-for-php-fcc-article">GitHub repo</a></p>
<h2 id="heading-project-how-to-use-php-to-rebuild-the-football-team-cards-project-of-the-updated-javascript-curriculum">Project: How to Use PHP to Rebuild the Football Team Cards Project of the Updated JavaScript Curriculum</h2>
<p>Before you start going through the steps to build the project, grab the starter code for the project in <a target="_blank" href="https://github.com/Ksound22/football-team-cards-php-rebuild">the starter branch of this GitHub repo</a>.</p>
<p>You can also take a look at <a target="_blank" href="https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures-v8/learn-modern-javascript-methods-by-building-football-team-cards/step-1">the football team cards project</a> to know what we are trying to achieve.</p>
<h3 id="heading-step-1-set-up-mongodb-atlas">Step 1: Set up MongoDB Atlas</h3>
<p>Log in to your MongoDB Atlas account and create a <code>football-team-cards</code> database. Feel free to create it in an existing project or a new one if you want. In the <code>football-team-cards</code> database, create a <code>footballers</code> collection.</p>
<p>In the <code>footballers</code> collection, click the "INSERT DOCUMENT" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-06-09-at-14.33.15.png" alt="Screenshot-2024-06-09-at-14.33.15" width="600" height="400" loading="lazy"></p>
<p>Then paste in the content of the <code>footballers.json</code> file in the starter branch of the project GitHub repo and click "Done".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-06-09-at-14.42.47.png" alt="Screenshot-2024-06-09-at-14.42.47" width="600" height="400" loading="lazy"></p>
<p>After that, your <code>footballers</code> collection should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-06-09-at-14.44.59.png" alt="Screenshot-2024-06-09-at-14.44.59" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-2-install-the-project-dependencies-with-composer">Step 2: Install the Project Dependencies with Composer</h3>
<p>Create a <code>football-team-cards-php</code> folder on your computer and open it with your favorite text editor. Open the same folder in your terminal and run the following commands:</p>
<pre><code class="lang-bash">composer require vlucas/phpdotenv 
composer require mongodb/mongodb
</code></pre>
<h3 id="heading-step-3-create-project-files">Step 3: Create Project Files</h3>
<p>Inside the <code>football-team-cards-php</code> folder, create the following files:</p>
<ul>
<li><p><code>.env</code></p>
</li>
<li><p><code>mongo_atlas_php_setup.php</code></p>
</li>
<li><p><code>index.php</code></p>
</li>
<li><p><code>styles.css</code></p>
</li>
</ul>
<p>In the <code>.env</code> file, you should have the MongoDB Atlas URI:</p>
<pre><code class="lang-bash">MDB_URI=<span class="hljs-string">"Your MongoDB Atlas connection string"</span>
</code></pre>
<p>In the <code>mongo_atlas_php_setup.php</code> file, you should connect to the database with this code:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;
$dotenv = Dotenv\Dotenv::createImmutable(<span class="hljs-keyword">__DIR__</span>);
$dotenv-&gt;load();


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMongoClient</span>(<span class="hljs-params"></span>)
</span>{
 <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MongoDB\Client($_ENV[<span class="hljs-string">'MDB_URI'</span>]);
}


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMongoCollection</span>(<span class="hljs-params">$database, $collection</span>)
</span>{
 $client = getMongoClient();
 <span class="hljs-keyword">return</span> $client-&gt;selectCollection($database, $collection);
}
</code></pre>
<p>In the code above, we are loading the environment variables and using a <code>getMongCollection</code> function to connect the database. Make sure you replace the connection string with your own.</p>
<p>Now, anytime you want to connect to a database, require the file, then pass the database and the collection names to the <code>getMongoCollection</code> function.</p>
<p>Copy the content of the <code>index.html</code> and <code>styles.css</code> files in the starter branch of the project GitHub repo and paste them into your <code>index.php</code> and <code>styles.css</code> files.</p>
<h3 id="heading-step-4-wrap-the-select-tag-in-a-form-element">Step 4: Wrap the <code>select</code> tag in a <code>form</code> Element</h3>
<p>Replace the existing <code>select</code> tag with the following:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"options-label"</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"players"</span>&gt;</span>Filter Teammates:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"position"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"players"</span> <span class="hljs-attr">onchange</span>=<span class="hljs-string">"this.form.submit()"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"all"</span>&gt;</span>All Players<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"nickname"</span>&gt;</span>Nicknames<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"forward"</span>&gt;</span>Position Forward<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"midfielder"</span>&gt;</span>Position Midfielder<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"defender"</span>&gt;</span>Position Defender<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"goalkeeper"</span>&gt;</span>Position Goalkeeper<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
     <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>This will let you make a <code>POST</code> request with the <code>name</code> attribute set to <code>position</code>. And with the <code>onchange</code> attribute of <code>this.form.submit()</code>, you'll be able to fetch footballers based on any of the options selected. More on this later.</p>
<h3 id="heading-step-5-create-the-logic-for-fetching-the-footballers-from-the-footballers-collection">Step 5: Create the Logic for Fetching the Footballers from the <code>footballers</code> Collection</h3>
<pre><code class="lang-php"><span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/mongo_atlas_php_setup.php'</span>;

$position = <span class="hljs-keyword">isset</span>($_POST[<span class="hljs-string">'position'</span>]) ? $_POST[<span class="hljs-string">'position'</span>] : <span class="hljs-string">'all'</span>;

$collection = getMongoCollection(<span class="hljs-string">'football-team-cards'</span>, <span class="hljs-string">'footballers'</span>);
$team = $collection-&gt;findOne([<span class="hljs-string">'team'</span> =&gt; <span class="hljs-string">'Argentina'</span>]);
$players = $team[<span class="hljs-string">'players'</span>]-&gt;getArrayCopy();
</code></pre>
<p>With the code above, we are:</p>
<ul>
<li><p>importing the database connection file</p>
</li>
<li><p>checking for <code>POST</code> data with the name on the <code>select</code> tag and setting a default value of <code>all</code> (the first option in the select element)</p>
</li>
<li><p>getting the database and collection in it</p>
</li>
<li><p>using the <code>findOne</code> method from MongoDB to get the team</p>
</li>
<li><p>and fetching the data as an array with <code>getArraCopy()</code> so we can loop through it</p>
</li>
</ul>
<p>At this point, you can print the <code>$players</code> variable with <code>print_r()</code> or <code>var_dump()</code> to see what it looks like. On my end, it looks like this when I ran the app with <code>php -S localhost:4000</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-06-09-at-16.24.47.png" alt="Screenshot-2024-06-09-at-16.24.47" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-6-create-the-logic-for-filtering-the-footballers-based-on-position">Step 6: Create the Logic for Filtering the Footballers Based on Position</h3>
<p>Remember we have to display the players based on whether they are goakeepers, defenders, midfielders, or forwards. To do that, we can utilize the code below:</p>
<pre><code class="lang-php">$filteredPlayers = $players;


<span class="hljs-keyword">if</span> ($position !== <span class="hljs-string">'all'</span>) {
 <span class="hljs-keyword">if</span> ($position === <span class="hljs-string">'nickname'</span>) {
   $filteredPlayers = array_filter($players, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$player</span>) </span>{
     <span class="hljs-keyword">return</span> !<span class="hljs-keyword">empty</span>($player[<span class="hljs-string">'nickname'</span>]);
   });
 } <span class="hljs-keyword">else</span> {
   $filteredPlayers = array_filter($players, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">$player</span>) <span class="hljs-title">use</span> (<span class="hljs-params">$position</span>) </span>{
     <span class="hljs-keyword">return</span> $player[<span class="hljs-string">'position'</span>] === $position;
   });
 }
}
</code></pre>
<p>At first, we are initializing <code>$filteredPlayers</code> to all the players. If the selected position is not <code>all</code>, we filter the players based on <code>nickname</code>. And if the selected position is not <code>nickname</code>, we filter the players to include only those whose position matches the selected <code>position</code>.</p>
<h3 id="heading-step-7-display-the-players-on-the-page-based-on-the-selected-position">Step 7: Display the Players on the Page Based on the Selected Position</h3>
<p>Now, all we need to do is set each option's value (all players, goalkeepers, defenders, midfielders, forwards) to <code>selected</code> if that option is matched. After that, we need to use <code>foreach</code> loop to do the proper display.</p>
<p>Here's one way you can set the value of each <code>option</code> to <code>selected</code>:</p>
<pre><code class="lang-php">&lt;option value=<span class="hljs-string">"all"</span> <span class="hljs-meta">&lt;?=</span> $position === <span class="hljs-string">'all'</span> ? <span class="hljs-string">'selected'</span> : <span class="hljs-string">''</span> <span class="hljs-meta">?&gt;</span>&gt;All Players&lt;/option&gt;
       &lt;option value=<span class="hljs-string">"nickname"</span> <span class="hljs-meta">&lt;?=</span> $position === <span class="hljs-string">'nickname'</span> ? <span class="hljs-string">'selected'</span> : <span class="hljs-string">''</span> <span class="hljs-meta">?&gt;</span>&gt;Nicknames&lt;/option&gt;
       &lt;option value=<span class="hljs-string">"forward"</span> <span class="hljs-meta">&lt;?=</span> $position === <span class="hljs-string">'forward'</span> ? <span class="hljs-string">'selected'</span> : <span class="hljs-string">''</span> <span class="hljs-meta">?&gt;</span>&gt;Forwards&lt;/option&gt;
       &lt;option value=<span class="hljs-string">"midfielder"</span> <span class="hljs-meta">&lt;?=</span> $position === <span class="hljs-string">'midfielder'</span> ? <span class="hljs-string">'selected'</span> : <span class="hljs-string">''</span> <span class="hljs-meta">?&gt;</span>&gt;Midfielders&lt;/option&gt;
       &lt;option value=<span class="hljs-string">"defender"</span> <span class="hljs-meta">&lt;?=</span> $position === <span class="hljs-string">'defender'</span> ? <span class="hljs-string">'selected'</span> : <span class="hljs-string">''</span> <span class="hljs-meta">?&gt;</span>&gt;Defenders&lt;/option&gt;
       &lt;option value=<span class="hljs-string">"goalkeeper"</span> <span class="hljs-meta">&lt;?=</span> $position === <span class="hljs-string">'goalkeeper'</span> ? <span class="hljs-string">'selected'</span> : <span class="hljs-string">''</span> <span class="hljs-meta">?&gt;</span>&gt;Goalkeepers&lt;/option&gt;
</code></pre>
<p>And here's how you can use the <code>foreach</code> loop to finally display the players selected:</p>
<pre><code class="lang-php">&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">cards</span>" <span class="hljs-title">id</span>="<span class="hljs-title">player</span>-<span class="hljs-title">cards</span>"&gt;
     &lt;?<span class="hljs-title">php</span> <span class="hljs-title">if</span> (<span class="hljs-title">empty</span>($<span class="hljs-title">filteredPlayers</span>)) : ?&gt;
       &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">No</span> <span class="hljs-title">players</span> <span class="hljs-title">found</span> <span class="hljs-title">for</span> <span class="hljs-title">the</span> <span class="hljs-title">selected</span> <span class="hljs-title">position</span>.&lt;/<span class="hljs-title">p</span>&gt;
     &lt;?<span class="hljs-title">php</span> <span class="hljs-title">else</span> : ?&gt;
       &lt;?<span class="hljs-title">php</span> <span class="hljs-title">foreach</span> ($<span class="hljs-title">filteredPlayers</span> <span class="hljs-title">as</span> $<span class="hljs-title">players</span>) : ?&gt;
         &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">player</span>-<span class="hljs-title">card</span>"&gt;
           &lt;<span class="hljs-title">h2</span>&gt;&lt;?= $<span class="hljs-title">players</span>['<span class="hljs-title">name</span>'] . ($<span class="hljs-title">players</span>['<span class="hljs-title">isCaptain</span>'] ? ' (<span class="hljs-title">Captain</span>)' : '') ?&gt;&lt;/<span class="hljs-title">h2</span>&gt;
           &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Position</span>: &lt;?= $<span class="hljs-title">players</span>['<span class="hljs-title">position</span>'] ?&gt;&lt;/<span class="hljs-title">p</span>&gt;
           &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Number</span>: &lt;?= $<span class="hljs-title">players</span>['<span class="hljs-title">number</span>'] ?&gt;&lt;/<span class="hljs-title">p</span>&gt;
           &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Nickname</span>: &lt;?= !<span class="hljs-title">empty</span>($<span class="hljs-title">players</span>['<span class="hljs-title">nickname</span>']) ? $<span class="hljs-title">players</span>['<span class="hljs-title">nickname</span>'] : '<span class="hljs-title">N</span>/<span class="hljs-title">A</span>' ?&gt;&lt;/<span class="hljs-title">p</span>&gt;
         &lt;/<span class="hljs-title">div</span>&gt;
       &lt;?<span class="hljs-title">php</span> <span class="hljs-title">endforeach</span> ?&gt;
     &lt;?<span class="hljs-title">php</span> <span class="hljs-title">endif</span> ?&gt;
   &lt;/<span class="hljs-title">div</span>&gt;</span>
</code></pre>
<p>Now, everything works as expected:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/football-team-cards.gif" alt="football-team-cards" width="600" height="400" loading="lazy"></p>
<p>You can grab the final code of the project in the main branch of this <a target="_blank" href="https://github.com/Ksound22/football-team-cards-php-rebuild">GitHub repo</a>.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Rebuilding the football team cards project with PHP and MongoDB Atlas shows just how powerful and flexible it can be to combine server-side scripting with a cloud-based NoSQL database.</p>
<p>The project not only highlights how smoothly PHP and MongoDB Atlas work together, but it also shows the advantages of using a cloud-based database like Atlas. Atlas offers scalability, high availability, and easy management, making it a great choice for modern web applications.</p>
<p>Whichever data-driven application you're making, these techniques that we used here to build the project and the initial CRUD app can help you out.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Migrate Your Local Data to MongoDB Atlas ]]>
                </title>
                <description>
                    <![CDATA[ Data forms the bedrock of our daily lives, as a lot of day-to-day decision-making is hinged on its existence. Just like energy, data can be transformed from one medium to another. So far, web development has become much more advanced, and data migrat... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/mongodb-data-migration/</link>
                <guid isPermaLink="false">66bb58cc0da5b03e481107d8</guid>
                
                    <category>
                        <![CDATA[ Cloud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi ]]>
                </dc:creator>
                <pubDate>Mon, 18 Mar 2024 14:40:31 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/mongoCloud.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Data forms the bedrock of our daily lives, as a lot of day-to-day decision-making is hinged on its existence. Just like energy, data can be transformed from one medium to another.</p>
<p>So far, web development has become much more advanced, and data migration and backup is an essential skill every web developer should have to help ensure continuity of data and preserve user information regardless of any circumstances.</p>
<p>For developers like me who prefer to test all their code features locally in a development environment before final deployment to the cloud, this tutorial would come in handy for you when faced with the challenge of migrating your locally stored MongoDB data to a cloud platform or any other platform.</p>
<p>The inspiration for this article is a result of the need for me to migrate the total JSON data on my local MongoDB Compass server to the cloud (MongoDB Atlas) for an ongoing project. I waded through the endless internet resources and documentation but couldn’t get a suitable, straightforward fix. With multiple trials and errors, I was able to succeed with the migration. This article should serve as the definitive guide you need to save you time and achieve fast results.</p>
<p>In this article, we'll delve into data management in MongoDB, data backup, and efficient data migration tools that ease up the entire process. This article is suited for people with intermediate to advanced knowledge of MongoDB and backend development. </p>
<p>If you have any difficulty with the terminologies used in this article, I would suggest studying the MongoDB documentation <a target="_blank" href="https://www.mongodb.com/docs/">here</a>. </p>
<p>Let’s begin.</p>
<h2 id="heading-introduction-to-mongodb">Introduction to MongoDB</h2>
<p>MongoDB is a non-relational NoSQL-based database that stores data via the document model in a JSON format. It’s quite popular, and ranks top among the most used databases worldwide.</p>
<p>It's also more code-friendly as it's currently the default database used by many JavaScript-based full stack and backend developers.</p>
<p>It has various database options, comprising both local database servers and a cloud-based Database-As-A-Platform. </p>
<p>A good example of this is the MongoDB Atlas. MongoDB Atlas is a flexible and scalable MongoDB implementation with strong cloud security.</p>
<p>It provides indexing, load balancing, and sharding, among other features. More information regarding it can be found <a target="_blank" href="https://www.mongodb.com/features">here</a>.</p>
<h2 id="heading-how-to-initialize-the-mongodb-server">How to Initialize the MongoDB Server</h2>
<p>You should have the MongoDB local server already installed. However, if you haven’t installed it, it can be downloaded <a target="_blank" href="https://www.mongodb.com/try/download/community">here</a>.</p>
<p>The MongoDB server can then be easily executable by adding its path to the environmental variables on Windows.</p>
<p>To initialize the MongoDB application, activate the command prompt and type in<br><code>Mongod</code></p>
<p><img src="https://hackmd.io/_uploads/r1aAf6gCp.jpg" alt="Mongo DB server running" width="600" height="400" loading="lazy">
<em>MongoDb server running</em></p>
<p>To explore the databases on the MongoDB server, open the MongoDB command shell and type <code>show dbs</code>  </p>
<p><img src="https://hackmd.io/_uploads/rJY2G6eC6.jpg" alt="The databases in my mongodb server" width="600" height="400" loading="lazy">
<em>The databses on the MongoDB server</em></p>
<p>This displays all the databases on the MongoDB server.</p>
<p>With this, let's go on to migrate one of these databases to the cloud.</p>
<h2 id="heading-how-to-back-up-data">How to Back Up Data</h2>
<p>To efficiently upload the database collections to the cloud, they must first be backed up.</p>
<p>To back up your database, you'll have to install an additional tool. Navigate back to the MongoDB downloads site and download the MongoDB database administration <a target="_blank" href="https://www.mongodb.com/try/download/database-tools">tools</a>.</p>
<p>This package contains a lot of database tools, such as <code>MongoExport</code>, <code>MongoImport</code>, <code>MongoDump</code>, and <code>MongoRestore</code>. </p>
<p>The above settings are applicable for users who have a version of MongoDB above version 4.4. MongoDB decided to release it as a stand-alone tool. For users whose version is less than version 4.4, these tools can be pre-installed in the MongoDB package.</p>
<p>Now, let's go on to the two major tools that would help facilitate the migration process: <code>MongoDump</code> and <code>MongoRestore</code>.</p>
<p>When <code>MongoDump</code> is executed on a database, it helps to create a backup database file in a binary-encoded JSON format (BSON). While the <code>MongoRestore</code> helps to return the backed-up database to MongoDB for usage.</p>
<p>Moving on, ensure that their package path is included in the environmental variables so as to guarantee efficient execution.</p>
<p>In order to back up a local database, open the MongoDB shell and then enter this command:</p>
<pre><code>Mongodump --db={TheNameOFYourDB} --collection={TheNameOfYourCollection} –out={The name <span class="hljs-keyword">of</span> the folder the backed up <span class="hljs-built_in">JSON</span> files would be located}
</code></pre><p>With this execution, you have successfully backed up your local MongoDB database.</p>
<h2 id="heading-how-to-set-up-a-mongodb-atlas">How to Set Up a MongoDB Atlas</h2>
<p>MongoDB Atlas is MongoDB cloud Database-As-A-Service cloud option accessible to its users at all times with little to no disruption.</p>
<p>Also, for most production apps that utilize the power of MongoDB on the server as a database tool, the easiest and most convenient provider of this solution is the MongoDB Atlas.</p>
<p>Hence, it is our choice to back up our MongoDB data to the cloud. I would assume you already have a MongoDB Atlas account, but you can still create one and then create a database that would serve as the recipient of the local database.</p>
<p>To set the account up, kindly navigate to the Atlas home page <a target="_blank" href="https://www.mongodb.com/atlas/database">here</a>. Create an account and you'll be directed to a dashboard where you can create new databases.  </p>
<p><img src="https://hackmd.io/_uploads/S15QNeGAp.jpg" alt="atllas" width="600" height="400" loading="lazy">
<em>MongoDb Atlas home page</em></p>
<p>You can, however, name it with any name you want. To complete the upload of the local MongoDB data to the cloud, navigate to the settings tab on the MongoDB Atlas database and click on the migrate data option. With this successfully done, let's now go on to complete the migration process.</p>
<h2 id="heading-how-to-migrate-your-data-to-the-cloud">How to Migrate Your Data to the Cloud</h2>
<p>To migrate your backed-up database to the cloud, <code>MongoImport</code> and <code>MongoExport</code> will be invoked.</p>
<p>In the command prompt, paste the migration code copied from the Atlas, and then execute it on the command prompt. With that, you should see a success text.</p>
<p>You can then check and refresh your cloud database to see the new files that have been uploaded there. Thereafter, you can connect the new cloud database to your backend application and run it successfully to get the same results on your local computer.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With this, we have come to the end of the tutorial. We hope you’ve learned about data management and migration in MongoDB, tools involved and all its intricacies. </p>
<p>Feel free to drop comments and questions, and also check out my other articles <a target="_blank" href="https://www.freecodecamp.org/news/author/oluwatobi/">here</a>. Till next time, keep on coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Filtering, Sorting, Limiting, and Pagination to Your Nest.js App ]]>
                </title>
                <description>
                    <![CDATA[ By Okure U. Edet If you are reading this article, you are probably a developer who has used an API to call data for your application. You may have also used features such as filtering and pagination to limit the amount of data you want to receive.  T... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-filtering-sorting-limiting-pagination-to-nestjs-app/</link>
                <guid isPermaLink="false">66d46089ffe6b1f641b5fa4b</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 05 Feb 2024 19:01:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/nestjs-app-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Okure U. Edet</p>
<p>If you are reading this article, you are probably a developer who has used an API to call data for your application. You may have also used features such as filtering and pagination to limit the amount of data you want to receive. </p>
<p>These API features are important when building your own API. They help ensure that your API is fast, secure, and easily understandable by the people using it.</p>
<p>In this article, you will build a simple expense API with Nest.js and MongoDB for a database. You will then implement filtering, sorting, limiting, and pagination to make your API faster and easy to use. Let's begin!</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-an-api">What is an API?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-nestjs-app">How to set up a Nest.js app</a></li>
<li><a class="post-section-overview" href="#heading-how-to-configure-mongodb">How to configure MongoDB</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-expense-endpoints">How to set up the expense endpoints</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-filtering-and-sorting">How to implement filtering and sorting</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-limiting-and-pagination">How to implement limiting and pagination</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-is-an-api">What is an API?</h2>
<p>APIs are the backbone of modern software development. API stands for Application Programming Interface, and it allows one piece of software to communicate with another piece of software. </p>
<p>Web APIs use the HTTP communication protocols to communicate with computers. There are different types of APIs, but we won't get into them here.</p>
<p>These days, it's common for web APIs to have design features such as filtering, sorting, limiting, and pagination to make the API faster, easier to use, and more secure. You will learn how to implement these features to make a better API in this article.</p>
<h2 id="heading-how-to-set-up-a-nestjs-app">How to Set Up a Nest.js App</h2>
<p>First of all, you will be building a simple expense CRUD API in Nestjs. Nestjs is a progressive Node.js framework for building modern APIs that's pretty easy to use.</p>
<p>To get started, open your command line and type out the following commands:</p>
<pre><code>$ npm i -g @nestjs/cli
$ nest <span class="hljs-keyword">new</span> expense-app
</code></pre><p>Follow the installation guide. This will generate a few boilerplate files for you. Then you can open your Nest.js app in an IDE of your choice.</p>
<h2 id="heading-how-to-configure-mongodb">How to Configure MongoDB</h2>
<p>Since MongoDB is our preferred database, it's important to configure it so you can use it in your app. First install the <code>@nestjs/mongoose</code> package:</p>
<pre><code>$ npm i @nestjs/mongoose mongoose
</code></pre><p>Once the installation is complete, go into your app module file and import the <code>MongooseModule</code>:</p>
<pre><code><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;
<span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;

@Module({
  <span class="hljs-attr">imports</span>: [MongooseModule.forRoot(<span class="hljs-string">`mongodb+srv://*******:*******@cluster0.30vt0jd.mongodb.net/expense-test-app`</span>)],
  <span class="hljs-attr">controllers</span>: [AppController],
  <span class="hljs-attr">providers</span>: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppModule</span> </span>{}
</code></pre><p>If you don't want to expose your string that way, you can create a <code>.env</code> file and store your database connection string in it. You will then need to install the <code>@nestjs/config</code> package which uses dotenv internally. </p>
<p>Inside your app module file, import the <code>ConfigModule</code>:</p>
<pre><code>@Module({
  <span class="hljs-attr">imports</span>: [
    ConfigModule.forRoot({ <span class="hljs-attr">envFilePath</span>: <span class="hljs-string">'.env'</span>, <span class="hljs-attr">isGlobal</span>: <span class="hljs-literal">true</span> }),
    MongooseModule.forRoot(process.env.DATABASE),
  ],
  <span class="hljs-attr">controllers</span>: [AppController],
  <span class="hljs-attr">providers</span>: [AppService],
})
</code></pre><p><code>isGlobal: true</code> is to make the module available everywhere in your application. <code>envFilePath</code> specifies the path to your <code>.env</code> file.</p>
<h2 id="heading-how-to-set-up-the-expense-endpoints">How to Set Up the Expense Endpoints</h2>
<p>You have configured MongoDB. Now it's time to set up the expense endpoints. </p>
<p>You can create a module in Nest.js by typing the following into the terminal: <code>nest generate module expenses</code>. You can also generate the controller like this: <code>nest generate controller expenses</code> and the service like this: <code>nest generate service expenses</code>. You should do all this in the src folder. </p>
<p>Go ahead and generate an expenses.schema.ts file. Inside the expenses.schema.ts file, create an expense schema with some validation.</p>
<pre><code><span class="hljs-keyword">import</span> { Prop, Schema, SchemaFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> mongoose, { HydratedDocument } <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;

<span class="hljs-keyword">export</span> type ExpenseDocument = HydratedDocument&lt;Expense&gt;;

@Schema()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expense</span> </span>{
  @Prop({
    <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Title is required'</span>],
  })
  <span class="hljs-attr">title</span>: string;

  @Prop({
    <span class="hljs-attr">min</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Amount is required'</span>],
  })
  <span class="hljs-attr">amount</span>: number;

  @Prop({
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Category is required'</span>],
  })
  <span class="hljs-attr">category</span>: string;

  @Prop({
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-built_in">Date</span>.now,
  })
  <span class="hljs-attr">incurred</span>: <span class="hljs-built_in">Date</span>;

  @Prop({ <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span> })
  <span class="hljs-attr">notes</span>: string;

  @Prop()
  <span class="hljs-attr">slug</span>: string;

  @Prop()
  <span class="hljs-attr">updated</span>: <span class="hljs-built_in">Date</span>;

  @Prop({
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-built_in">Date</span>.now,
  })
  <span class="hljs-attr">created</span>: <span class="hljs-built_in">Date</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ExpenseSchema = SchemaFactory.createForClass(Expense);
</code></pre><p>The properties in this schema include title, amount, category, notes, and slug.</p>
<p>After doing this, you want to register the expense model in the expenses.module.ts file:</p>
<pre><code><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ExpensesController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.controller'</span>;
<span class="hljs-keyword">import</span> { ExpensesService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.service'</span>;
<span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { Expense, ExpenseSchema } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.schema'</span>;

@Module({
  <span class="hljs-attr">imports</span>: [
    MongooseModule.forFeature([{ <span class="hljs-attr">name</span>: Expense.name, <span class="hljs-attr">schema</span>: ExpenseSchema }]),
  ],
  <span class="hljs-attr">controllers</span>: [ExpensesController],
  <span class="hljs-attr">providers</span>: [ExpensesService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExpensesModule</span> </span>{}
</code></pre><p>Once you've registered the schema, you can then inject the <code>Expense</code> model into the <code>ExpensesService</code> by using an <code>@InjectModel()</code> decorator.</p>
<pre><code><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { InjectModel } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { Expense } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.schema'</span>;
<span class="hljs-keyword">import</span> { Model } <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;
<span class="hljs-keyword">import</span> { ExpenseDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/expense.dto'</span>;

@Injectable()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExpensesService</span> </span>{
  <span class="hljs-keyword">constructor</span>(
    @InjectModel(Expense.name) private expenseModel: Model&lt;Expense&gt;,
  ) {}

  <span class="hljs-keyword">async</span> createExpense(data: ExpenseDto) {
    <span class="hljs-keyword">const</span> expense = <span class="hljs-built_in">this</span>.expenseModel.create(data);

    <span class="hljs-keyword">return</span> expense;
  }

  <span class="hljs-keyword">async</span> getExpenses() {
    <span class="hljs-keyword">const</span> expenses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.expenseModel.find();

    <span class="hljs-keyword">return</span> expenses;
  }
}
</code></pre><p>In the <code>ExpensesService</code> file, we injected the <code>Expense</code> model as a dependency using the <code>@InjectModel()</code> decorator. Once you've done this, you then go ahead and define a function that creates an expense and a function that gets all expenses.</p>
<p>In your controller, add the following code:</p>
<pre><code><span class="hljs-keyword">import</span> { Body, Controller, Get, Post, Res } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ExpensesService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.service'</span>;
<span class="hljs-keyword">import</span> { ExpenseDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/expense.dto'</span>;

@Controller(<span class="hljs-string">'expenses'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExpensesController</span> </span>{
  <span class="hljs-keyword">constructor</span>(private readonly expenseService: ExpensesService) {}

  @Post()
  <span class="hljs-keyword">async</span> createExpense(@Body() data: ExpenseDto, @Res() response: any) {
    <span class="hljs-keyword">const</span> expense = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.expenseService.createExpense(data);
    <span class="hljs-built_in">console</span>.log(expense);

    <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">201</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'success'</span>,
      <span class="hljs-attr">data</span>: expense,
    });
  }

  @Get()
  <span class="hljs-keyword">async</span> getExpenses(@Res() response: any) {
    <span class="hljs-keyword">const</span> expenses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.expenseService.getExpenses();

    <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">200</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'success'</span>,
      <span class="hljs-attr">data</span>: expenses,
    });
  }
}
</code></pre><p>If you're getting a dependency error, navigate to your <code>app.module.ts</code> file and remove <code>ExpenseController</code> from the <code>controllers</code> array.</p>
<p>You can test the endpoint on Postman.</p>
<h2 id="heading-how-to-implement-filtering-and-sorting">How to Implement Filtering and Sorting</h2>
<p>Now that you have successfully set up the expense endpoints, it's time to implement filtering and sorting features in the API.</p>
<h3 id="heading-filtering">Filtering</h3>
<p>Filtering is essentially done in the same way we do it in Node.js.</p>
<p>Inside your src directory, create a new folder called <code>Utils</code> and inside that folder create a new file called <code>apiFeatures.ts</code>.</p>
<p>Inside this file, define a class called <code>APIFeatures</code>. This class will contain methods that will house the API features you'll implement.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">APIFeatures</span> </span>{
  <span class="hljs-attr">mongooseQuery</span>: any;
  queryString: any;

  <span class="hljs-keyword">constructor</span>(mongooseQuery: any, queryString: any) {
    <span class="hljs-built_in">this</span>.mongooseQuery = mongooseQuery;
    <span class="hljs-built_in">this</span>.queryString = queryString;
  }

  filter() {
    <span class="hljs-comment">// 1) Filtering</span>
    <span class="hljs-keyword">const</span> queryObj = { ...this.queryString };
    <span class="hljs-keyword">const</span> excludedFields = [<span class="hljs-string">'page'</span>, <span class="hljs-string">'sort'</span>, <span class="hljs-string">'limit'</span>, <span class="hljs-string">'fields'</span>];
    excludedFields.forEach(<span class="hljs-function">(<span class="hljs-params">fields</span>) =&gt;</span> {
      <span class="hljs-keyword">delete</span> queryObj[fields];
    });
    <span class="hljs-comment">// console.log(queryObj);</span>

    <span class="hljs-comment">//2) Advanced filtering</span>
    <span class="hljs-keyword">let</span> queryStr = <span class="hljs-built_in">JSON</span>.stringify(queryObj);
    queryStr = queryStr.replace(<span class="hljs-regexp">/\b(gte|gt|lte|lt)\b/g</span>, <span class="hljs-function">(<span class="hljs-params">match</span>) =&gt;</span> <span class="hljs-string">`$<span class="hljs-subst">${match}</span>`</span>);
    <span class="hljs-comment">//console.log(JSON.parse(queryStr));</span>

    <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.find(<span class="hljs-built_in">JSON</span>.parse(queryStr));

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
}
</code></pre><p>In the filter method, you created a hard copy of the <code>req.query</code>. It's passed as an argument in the form of <code>queryString</code>. </p>
<p>Before filtering, you want to exclude certain special fileds such as <code>page</code>, <code>sort</code>, <code>limits</code> and <code>fields</code>. These fields are deleted from the hard copy of the object which is stored in the variable <code>queryObj</code>. You also want to use MongoDB operators such as <code>gt</code> or <code>gte</code>.</p>
<p>For example, on Postman this is how you type in the query: <code>?amount[gt]=100</code>
In MongoDB, It'll look like this: <code>{ amount: { $gt: 100 } }</code>. In the filter method, we added a <code>$</code> sign to the operators using a regular expression.</p>
<p>After that, the object is parsed using <code>JSON.parse()</code> method and it is then passed into the Mongoose query function. Make sure you return the whole class itself by typing <code>return this</code>.</p>
<h3 id="heading-sorting">Sorting</h3>
<p>As you can see, implementing fitering is quite easy in Nest.js as it is in Node.js.</p>
<p>Now it's time to implement sorting. Inside the <code>APIFeatures</code> class, define another function called sorting.</p>
<pre><code>  sorting() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.queryString.sort) {
      <span class="hljs-keyword">const</span> sortBy = <span class="hljs-built_in">this</span>.queryString.sort.split(<span class="hljs-string">','</span>).join(<span class="hljs-string">' '</span>);
      <span class="hljs-comment">// console.log(sortBy);</span>
      <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.sort(sortBy);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.sort(<span class="hljs-string">'-created'</span>);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
</code></pre><p>The above method checks if a sort property exists on the query object. If it does, you split the string by a <code>,</code> in case there are multiple sort queries. Then you join it by a <code>' '</code>. </p>
<p>Once you've done this, you chain it to the Mongoose query with a sort method which exists on all documents. The else block sorts the document by the date it was created in case the user does not specify any sort query.</p>
<h2 id="heading-how-to-implement-limiting-and-pagination">How to Implement Limiting and Pagination</h2>
<p>Congrats! You have implemented filtering and sorting. Now it's time to implement limiting and pagination.</p>
<h3 id="heading-limiting">Limiting</h3>
<p>To limit fields, you can call the <code>select()</code> method on the Mongoose query.</p>
<p>Define another method in the class:</p>
<pre><code> limit() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.queryString.fields) {
      <span class="hljs-keyword">const</span> fields = <span class="hljs-built_in">this</span>.queryString.fields.split(<span class="hljs-string">','</span>).join(<span class="hljs-string">' '</span>);

      <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.select(fields);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.select(<span class="hljs-string">'-__v'</span>);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
</code></pre><p>And there you go.</p>
<h3 id="heading-pagination">Pagination</h3>
<p>To implement pagination, you want to get the <code>page</code> and <code>limit</code> from the query object. You then want to skip certain number of documents to get to the page you want. There is a <code>skip()</code> method and a <code>limit()</code> method on the Mongoose query.</p>
<pre><code>  pagination() {
    <span class="hljs-comment">// get the page and convert it to a number. If no page set default to 1</span>
    <span class="hljs-keyword">const</span> page = <span class="hljs-built_in">this</span>.queryString.page * <span class="hljs-number">1</span> || <span class="hljs-number">1</span>;

    <span class="hljs-comment">// get limit and if no limit, set limit to 100</span>
    <span class="hljs-keyword">const</span> limit = <span class="hljs-built_in">this</span>.queryString.limit * <span class="hljs-number">1</span> || <span class="hljs-number">100</span>;

    <span class="hljs-comment">// calculate skip value</span>
    <span class="hljs-keyword">const</span> skip = (page - <span class="hljs-number">1</span>) * limit;

    <span class="hljs-comment">// chain it to the mongoose query.</span>
    <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.skip(skip).limit(limit);

    <span class="hljs-comment">// return the object</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
</code></pre><p>Once you've done this, you want to call the <code>APIfeatures</code> class in your <code>ExpensesService</code> class in your expenses.service.ts file.</p>
<p>Replace your <code>getExpenses</code> function with this code:</p>
<pre><code> <span class="hljs-keyword">async</span> getExpenses(query?: any) {
    <span class="hljs-keyword">const</span> features = <span class="hljs-keyword">new</span> APIFeatures(<span class="hljs-built_in">this</span>.expenseModel.find(), query)
      .filter()
      .sort()
      .limit()
      .pagination();
    <span class="hljs-comment">//Execute the query</span>
    <span class="hljs-keyword">const</span> expenses = <span class="hljs-keyword">await</span> features.mongooseQuery;

    <span class="hljs-keyword">return</span> expenses;
  }
</code></pre><p>In the function, it is possible to chain all these methods in the <code>APIFeatures</code> class because each method returns the object.</p>
<p>In your expenses.controller.ts file, your <code>getExpenses</code> function should look like this:</p>
<pre><code>  @Get()
  <span class="hljs-keyword">async</span> getExpenses(@Res() response: any, @Req() request: any) {
    <span class="hljs-keyword">const</span> expenses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.expenseService.getExpenses(request.query);

    <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">200</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'success'</span>,
      <span class="hljs-attr">data</span>: expenses,
    });
  }
</code></pre><p>Now run the application with <code>npm start:dev</code> and test your API features in Postman.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, you have learned how to implement sorting, filtering, limiting, and pagination in your Nest.js applications. </p>
<p>With this knowledge, you can go ahead and implement these features in your personal projects built using Nest.js.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
