<?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[ mongoose - 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[ mongoose - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 19:41:27 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/mongoose/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <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 Test Your Express.js and Mongoose Apps with Jest and SuperTest ]]>
                </title>
                <description>
                    <![CDATA[ By Rakesh Potnuru Testing is a vital part of software development. The sooner you start testing, the better.  In this article, I'll show you how to write tests for your NodeJs/ExpressJS and MongoDB/Mongoose applications with Jest and Supertest. Let's... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-test-in-express-and-mongoose-apps/</link>
                <guid isPermaLink="false">66d460c9787a2a3b05af43f6</guid>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Jest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 27 Sep 2022 23:26:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/how-to-write-tests.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rakesh Potnuru</p>
<p>Testing is a vital part of software development. The sooner you start testing, the better. </p>
<p>In this article, I'll show you how to write tests for your NodeJs/ExpressJS and MongoDB/Mongoose applications with <strong>Jest</strong> and <strong>Supertest</strong>.</p>
<h2 id="heading-lets-get-started">Let's get started</h2>
<p>First let's set up a demo Express.js app.</p>
<p>Let's say we are building a backend REST API for an eCommerce application.</p>
<p>This app should:</p>
<ul>
<li>Get all the products</li>
<li>Get a product by id</li>
<li>Add product(s) to the database</li>
<li>Delete product(s) from the database</li>
<li>Update product information</li>
</ul>
<h2 id="heading-expressjs-app-set-up">Express.js App Set Up</h2>
<h3 id="heading-step-1-project-set-up">Step 1: Project set up</h3>
<p>First, create a folder and start a blank application with <code>npm</code>.</p>
<pre><code class="lang-bash">npm init
</code></pre>
<p>Fill all the details it asks for.</p>
<p>Then, install <code>express</code>, <code>mongoose</code>, <code>axios</code> and <code>dotenv</code> with the following command:</p>
<pre><code class="lang-bash">npm i express mongoose axios dotenv
</code></pre>
<p>Here's a link to the <a target="_blank" href="https://github.com/itsrakeshhq/jest-tests-demo/blob/a1725cb3379f78a03cf8d3d4cfa22127469e8b50/package.json">package.json</a> on my GitHub.</p>
<h3 id="heading-step-2-create-the-boilerplate">Step 2: Create the boilerplate</h3>
<p>Let's create all the folders and files and then fill them with some boilerplate code.</p>
<p>This is how your folder hierarchy should look:</p>
<pre><code class="lang-bash">.
├── controllers
│   └── product.controller.js
├── models
│   └── product.model.js
├── routes
│   └── product.route.js
├── package-lock.json
├── package.json
├── .env
├── app.js
└── server.js
</code></pre>
<p>Use these files' code by copying and pasting. Analyze the code and flow as best you can.</p>
<ul>
<li><code>[product.controller.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/controllers/product.controller.js)</code></li>
<li><code>[product.model.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/models/product.model.js)</code></li>
<li><code>[product.route.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/routes/product.route.js)</code></li>
<li><code>[app.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/app.js)</code> </li>
<li><code>[server.js](https://github.com/itsrakeshhq/jest-tests-demo/blob/main/server.js)</code></li>
</ul>
<h3 id="heading-step-3-database-setup">Step 3: Database setup</h3>
<p>I advise using two databases for a project—one for testing, the other for development. But just one database will be sufficient for learning purposes.</p>
<p>First, create a <a target="_blank" href="https://mongodb.com">MongoDB</a> account or log in.</p>
<p>Then create a new project. Give it a name and press the <strong>Next</strong> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-205148.png" alt="Naming the project" width="600" height="400" loading="lazy">
<em>Naming the project</em></p>
<p>Then click <strong>Create Project</strong> after that.</p>
<p>We must create a database in the following window by selecting a cloud provider, a location, and specs. So press <strong>Build a Database</strong> to get going.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-205911.png" alt="Build a database" width="600" height="400" loading="lazy">
<em>Build a database</em></p>
<p>Choose "Shared" because it is sufficient for learning purposes. And then click <strong>Create</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-211701.png" alt="Choose a deployment option" width="600" height="400" loading="lazy">
<em>Choose a deployment option</em></p>
<p>Next, select "aws" as your cloud provider and the region that is closest to you. Following your selection, click <strong>Create Cluster</strong>.</p>
<p>The cluster's formation will take some time. Create a user to access your database in the meanwhile.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-212537.png" alt="Create Superuser" width="600" height="400" loading="lazy">
<em>Create Superuser</em></p>
<p>Choose "My Local Environment" because we are developing our application. You can then add an IP addresses. To conclude, click <strong>Close</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/Screenshot-2022-09-26-213347.png" alt="Add IP addresses" width="600" height="400" loading="lazy">
<em>Add IP addresses</em></p>
<p>You will receive a URI string after the database is set up, which we'll use to connect to the database. The string appears as follows:</p>
<pre><code class="lang-bash">mongodb+srv://&lt;YOUR_USERNAME&gt;:&lt;YOUR_PASSWORD&gt;@&lt;YOUR_CLUSTER_URL&gt;/&lt;DATABASE_NAME&gt;?retryWrites=<span class="hljs-literal">true</span>&amp;w=majority
</code></pre>
<p>Put this string in the <code>.env</code> file.</p>
<pre><code class="lang-bash">MONGODB_URI=your database string
</code></pre>
<p>Now we're ready to start testing our app.</p>
<h2 id="heading-how-to-write-tests-with-jest-and-supertest">How to Write Tests with Jest and SuperTest</h2>
<h3 id="heading-step-1-install-packages">Step 1: Install packages</h3>
<p>You need three npm packages to begin writing tests: <code>jest</code>, <code>supertest</code>, and <code>cross-env</code>. You can install them like this:</p>
<pre><code class="lang-bash">npm i jest supertest cross-env
</code></pre>
<ul>
<li><code>jest</code>: Jest is a framework for testing JavaScript code. Unit testing is the main usage of it.</li>
<li><code>supertest</code>: Using Supertest, we can test endpoints and routes on HTTP servers.</li>
<li><code>cross-env</code>: You can set environmental variables inline within a command using cross-env.</li>
</ul>
<h3 id="heading-step-2-add-test-script">Step 2: Add test script</h3>
<p>Open your <code>package.json</code> file and add the test script to the scripts.</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"cross-env NODE_ENV=test jest --testTimeout=5000"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"node server.js"</span>,
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"nodemon server.js"</span>
},
</code></pre>
<p>In this case, we're using <code>cross-env</code> to set environment variables, <code>jest</code> to execute test suites, and <code>testTimeout</code> is set to <code>5000</code> because certain requests might take a while to finish.</p>
<h3 id="heading-step-3-start-writing-tests">Step 3: Start writing tests</h3>
<p>First, create a folder called <code>tests</code> at the application's root, and then create a file there called <code>product.test.js</code>. Jest searches for the folder <code>tests</code> at the project's root when you do <code>npm run test</code>. As a result, you must place your test files in the <code>tests</code> folder.</p>
<p>Next, import the <code>supertest</code> and <code>mongoose</code> packages into the test file.</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> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"supertest"</span>);
</code></pre>
<p>Import <code>dotenv</code> to load environment variables, and import <code>app.js</code> as that is where our application starts.</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> request = <span class="hljs-built_in">require</span>(<span class="hljs-string">"supertest"</span>);
<span class="hljs-keyword">const</span> app = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../app"</span>);

<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();
</code></pre>
<p>You'll need to connect and disconnect the database before and after each test (because we don't require the database once testing is complete).</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* Connecting to the database before each test. */</span>
beforeEach(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> mongoose.connect(process.env.MONGODB_URI);
});

<span class="hljs-comment">/* Closing database connection after each test. */</span>
afterEach(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> mongoose.connection.close();
});
</code></pre>
<p>Now you can write your first unit test.</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">"GET /api/products"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should return all products"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).get(<span class="hljs-string">"/api/products"</span>);
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.length).toBeGreaterThan(<span class="hljs-number">0</span>);
  });
});
</code></pre>
<p>In the above code, </p>
<ul>
<li>We use <code>describe</code> to describe the unit test. Even though it is not required, it will be useful to identify tests in test results.</li>
<li>In <code>it</code>, we write the actual test code. Tell what the test performs in the first argument, and then in the second argument, write a callback function that contains the test code.</li>
<li>In the callback function, the request is sent to the endpoint first, and the expected and actual responses are then compared. The test passes if both answers match, else, it fails. ✨ As simple as that ✨.</li>
</ul>
<p>You can write tests for all the endpoints in the same manner.</p>
<pre><code class="lang-javascript">describe(<span class="hljs-string">"GET /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should return a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).get(
      <span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>
    );
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.name).toBe(<span class="hljs-string">"Product 1"</span>);
  });
});

describe(<span class="hljs-string">"POST /api/products"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should create a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).post(<span class="hljs-string">"/api/products"</span>).send({
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Product 2"</span>,
      <span class="hljs-attr">price</span>: <span class="hljs-number">1009</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"Description 2"</span>,
    });
    expect(res.statusCode).toBe(<span class="hljs-number">201</span>);
    expect(res.body.name).toBe(<span class="hljs-string">"Product 2"</span>);
  });
});

describe(<span class="hljs-string">"PUT /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should update a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app)
      .patch(<span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>)
      .send({
        <span class="hljs-attr">name</span>: <span class="hljs-string">"Product 4"</span>,
        <span class="hljs-attr">price</span>: <span class="hljs-number">104</span>,
        <span class="hljs-attr">description</span>: <span class="hljs-string">"Description 4"</span>,
      });
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
    expect(res.body.price).toBe(<span class="hljs-number">104</span>);
  });
});

describe(<span class="hljs-string">"DELETE /api/products/:id"</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">"should delete a product"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> request(app).delete(
      <span class="hljs-string">"/api/products/6331abc9e9ececcc2d449e44"</span>
    );
    expect(res.statusCode).toBe(<span class="hljs-number">200</span>);
  });
});
</code></pre>
<p>Then run <code>npm run test</code> to run the test suites (suite - test file).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-428.png" alt="Image" width="600" height="400" loading="lazy">
<em>Test results</em></p>
<p>And that's it! You now know how to test your Express/Mongoose apps with Jest and SuperTest.</p>
<p>Now go forth and create new tests for your apps. :)</p>
<p>If you have any questions, feel free to message me on <a target="_blank" href="https://twitter.com/rakesh_at_tweet">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use MongoDB + Mongoose with Node.js – Best Practices for Back End Devs ]]>
                </title>
                <description>
                    <![CDATA[ By Mehul Mohan MongoDB is undoubtedly one of the most popular NoSQL database choices today. And it has a great community and ecosystem.  In this article, we'll review some of the best practices to follow when you're setting up MongoDB and Mongoose wi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/mongodb-mongoose-node-tutorial/</link>
                <guid isPermaLink="false">66d46068ffe6b1f641b5fa42</guid>
                
                    <category>
                        <![CDATA[ Back end development  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 27 Oct 2020 00:17:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/10/node-mongodb-fundamentals.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Mehul Mohan</p>
<p>MongoDB is undoubtedly one of the most popular NoSQL database choices today. And it has a great community and ecosystem. </p>
<p>In this article, we'll review some of the best practices to follow when you're setting up MongoDB and Mongoose with Node.js.</p>
<h2 id="heading-pre-requisites-for-this-article">Pre-requisites for this article</h2>
<p>This article is one of the part codedamn's <a target="_blank" href="https://codedamn.com/learning-paths/backend">backend learning path</a>, where we start from backend basics and cover them in detail. Therefore I assume you have some experience with JavaScript (and Node.js) already. </p>
<p>Currently we are here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot-2020-10-20-at-9.29.47-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you have very little experience with Node.js/JavaScript or the back end in general, <a target="_blank" href="https://codedamn.com/learning-paths/backend">this is probably a good place to start</a>. You can also find a <a target="_blank" href="https://codedamn.com/learn/node-mongodb-fundamentals">free course on Mongoose + MongoDB + Node.js here</a>. Let's dive in.</p>
<h2 id="heading-why-do-you-need-mongoose">Why do you need Mongoose?</h2>
<p>To understand why we need Mongoose, let's understand how MongoDB (and a database) works on the architecture level.</p>
<ul>
<li>You have a database server (MongoDB community server, for example)</li>
<li>You have a Node.js script running (as a process)</li>
</ul>
<p>MongoDB server listens on a TCP socket (usually), and your Node.js process can connect to it using a TCP connection. </p>
<p>But on the top of TCP, MongoDB also has its own protocol for understanding what exactly the client (our Node.js process) wants the database to do.</p>
<p>For this communication, instead of learning the messages we have to send on the TCP layer, we abstract that away with the help of a "driver" software, called MongoDB driver in this case. MongoDB driver is available as an <a target="_blank" href="https://www.npmjs.com/package/mongodb">npm package here</a>.</p>
<p>Now remember, the MongoDB driver is responsible for connecting and abstracting the low level communication request/responses from you – but this only gets you so far as a developer. </p>
<p>Because MongoDB is a schemaless database, it gives you way more power than you need as a beginner. More power means more surface area to get things wrong. You need to reduce your surface area of bugs and screw-ups you can make in your code. You need something more.</p>
<p>Meet Mongoose. Mongoose is an abstraction over the native MongoDB driver (the npm package I mentioned above). </p>
<p>The general rule of thumb with abstractions (the way I understand) is that with every abstraction you lose some low-level operation power. But that doesn't necessarily mean it is bad. Sometimes it boosts productivity 1000x+ because you never really need to have full access to the underlying API anyway.</p>
<p>A good way to think about it is you technically create a realtime chat app both in C and in Python. </p>
<p>The Python example would be much easier and faster for you as a developer to implement with higher productivity. </p>
<p>C <em>might</em> be more efficient, but it'll come at a huge cost in productivity/speed of development/bugs/crashes. Plus, for the most part you don't need to have the power C gives you to implement websockets.</p>
<p>Similarly, with Mongoose, you can limit your surface area of lower level API access, but unlock a lot of potential gains and good DX.</p>
<h2 id="heading-how-to-connect-mongoose-mongodb">How to connect Mongoose + MongoDB</h2>
<p>Firstly, let's quickly see how you should connect to your MongoDB database in 2020 with Mongoose:</p>
<pre><code class="lang-js">mongoose.connect(DB_CONNECTION_STRING, {
    <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useUnifiedTopology</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useCreateIndex</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">useFindAndModify</span>: <span class="hljs-literal">false</span>
})
</code></pre>
<p>This connection format makes sure that you're using the new URL Parser from Mongoose, and that you are not using any deprecated practices. You can read in depth about all these deprecation messages <a target="_blank" href="https://mongoosejs.com/docs/deprecations.html">here</a> if you like.</p>
<h2 id="heading-how-to-perform-mongoose-operations">How to perform Mongoose operations</h2>
<p>Let's now go ahead and quickly discuss operations with Mongoose, and how you should perform them.</p>
<p>Mongoose gives you options for two things:</p>
<ol>
<li>Cursor-based querying</li>
<li>Full fetching query</li>
</ol>
<h3 id="heading-cursor-based-querying">Cursor-based querying</h3>
<p>Cursor-based querying means that you work with a single record at a time while you fetch a single or a batch of documents at a time from the database. This is an efficient way of working with huge amounts of data in a limited memory environment. </p>
<p>Imagine that you have to parse documents of 10GB in total size on a 1GB/1core cloud server. You cannot fetch the whole collection because that will not fit on your system. Cursor is a good (and the only?) option here.</p>
<h3 id="heading-full-fetching-querying">Full fetching querying</h3>
<p>This is the type of query where you get the full response of your query all at once. For the most part, this is what you'll be using. Therefore, we'll be focusing mostly on this method here.</p>
<h2 id="heading-how-to-use-mongoose-models">How to use Mongoose Models</h2>
<p>Models are the superpower of Mongoose. They help you enforce "schema" rules and provide a seamless integration of your Node code into database calls. </p>
<p>The very first step is to define a good model:</p>
<pre><code><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> CompletedSchema = <span class="hljs-keyword">new</span> mongoose.Schema(
    {
        <span class="hljs-attr">type</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">enum</span>: [<span class="hljs-string">'course'</span>, <span class="hljs-string">'classroom'</span>], <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
        <span class="hljs-attr">parentslug</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">slug</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">userid</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">collection</span>: <span class="hljs-string">'completed'</span> }
)

CompletedSchema.index({ <span class="hljs-attr">slug</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">userid</span>: <span class="hljs-number">1</span> }, { <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span> })

<span class="hljs-keyword">const</span> model = mongoose.model(<span class="hljs-string">'Completed'</span>, CompletedSchema)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> model
</code></pre><p>This is one trimmed down example directly from codedamn's codebase. A few interesting things you should note here:</p>
<ol>
<li>Try to keep <code>required: true</code> on all fields which are required. This can be a huge pain saver for you if you don't use a static type checking system like TypeScript to assist you with correct property names while creating an object. Plus the free validation is super cool, too.</li>
<li>Define indexes and unique fields. <code>unique</code> property can also be added within a schema. Indexes are a broad topic, so I will not go into depth here. But on a large scale they can really help you to speed up your queries a lot.</li>
<li>Define a collection name explicitly. Although Mongoose can automatically give a collection name based on the name of model (<code>Completed</code> here, for example), this is way too much abstraction in my opinion. You should at least know about your database names and collections in your codebase.</li>
<li>Restrict values if you can, using enums.</li>
</ol>
<h2 id="heading-how-to-perform-crud-operations">How to perform CRUD Operations</h2>
<p>CRUD means <strong>C</strong>reate, <strong>R</strong>ead, <strong>U</strong>pdate and <strong>D</strong>elete. These are the four fundamental options with which you can perform any sort of data manipulation in a database. Let's quickly see some examples of these operations.</p>
<h3 id="heading-the-create-operation">The Create Operation</h3>
<p>This simply means creating a new record in a database. Let's use the model we defined above to create a record:</p>
<pre><code class="lang-js"><span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> CompletedSchema.create(record)
} <span class="hljs-keyword">catch</span>(error) {
    <span class="hljs-built_in">console</span>.error(error)
    <span class="hljs-comment">// handle the error</span>
}
</code></pre>
<p>Again, a few pointers here:</p>
<ol>
<li>Use async-await instead of callbacks (nice on the eyes, no ground breaking performance benefit as such)</li>
<li>Use try-catch blocks around queries because your query <em>can</em> fail for a number of reasons (duplicate record, incorrect value, and so on)</li>
</ol>
<h3 id="heading-the-read-operation">The Read Operation</h3>
<p>This means reading existing values from the database. it's simple just like it sounds, but there are a couple of gotchas you should know with Mongoose:</p>
<pre><code><span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> CompletedSchema.find(info).lean()
</code></pre><ol>
<li>Can you see the <code>lean()</code> function call there? It is super useful for performance. By default, Mongoose processes the returned document(s) from the database and adds its <em>magical</em> methods on it (for example <code>.save</code>)</li>
<li>When you use <code>.lean()</code>, Mongoose returns plain JSON objects instead of memory and resource heavy documents. Makes queries faster and less expensive on your CPU, too.</li>
<li>However, you can omit <code>.lean()</code> if you are actually thinking of updating data (we'll see that next)</li>
</ol>
<h3 id="heading-the-update-operation">The Update Operation</h3>
<p>If you already have a Mongoose document with you (without firing with <code>.lean()</code>), you can simply go ahead and modify the object property, and save it using <code>object.save()</code>:</p>
<pre><code><span class="hljs-keyword">const</span> doc = <span class="hljs-keyword">await</span> CompletedSchema.findOne(info)
doc.slug = <span class="hljs-string">'something-else'</span>
<span class="hljs-keyword">await</span> doc.save()
</code></pre><p>Remember that here, there are two database calls made. The first one is on <code>findOne</code> and the second one is on <code>doc.save</code>. </p>
<p>If you can, you should always reduce the number of requests hitting the database (because if you're comparing memory, network, and disk, network is almost always the slowest).</p>
<p>In the other case, you can use a query like this:</p>
<pre><code><span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> CompletedSchema.updateOne(&lt;condition&gt;, &lt;query&gt;).lean()
</code></pre><p>and it will only make a single call to the database.</p>
<h3 id="heading-the-delete-operation">The Delete Operation</h3>
<p>Delete is also straightforward with Mongoose. Let's see how you can delete a single document:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> CompletedSchema.deleteOne(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">condition</span>&gt;</span>)</span>
</code></pre>
<p>Just like <code>updateOne</code>, <code>deleteOne</code> also accepts the first argument as the matching condition for the document. </p>
<p>There is also another method called <code>deleteMany</code> which should be used only when you know you want to delete multiple documents. </p>
<p>In any other case, always use <code>deleteOne</code> to avoid accidental multiple deletes, especially when you're trying to execute queries yourself. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This article was a simple introduction to the Mongoose and MongoDB world for Node.js developers. </p>
<p>If you enjoyed this article, you can step up your game even more as a developer by following the <a target="_blank" href="https://codedamn.com/learning-paths/backend">codedamn backend learning path</a>. Please feel free to reach out to me on <a target="_blank" href="https://twitter.com/mehulmpt">Twitter</a> for any feedback!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn How to Deploy a Full Stack Web App with Heroku ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan Building a full stack web app is no mean feat. Learning to deploy one to production so that you can share it with the world can add an additional layer of complexity. In this new tutorial, we'll learn how to deploy a full stack MEVN a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-deploy-a-full-stack-web-app-with-heroku/</link>
                <guid isPermaLink="false">66d851ef8acc348be2a441c2</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Back end development  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Heroku ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 22 Jun 2020 01:32:32 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9a22740569d1a4ca23bc.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>Building a full stack web app is no mean feat. Learning to deploy one to production so that you can share it with the world can add an additional layer of complexity.</p>
<p>In this new tutorial, we'll learn how to deploy a <a target="_blank" href="https://www.freecodecamp.org/news/build-a-full-stack-mevn-app/">full stack MEVN app</a> to Heroku!</p>
<p>Follow along (46 minute watch):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/rUSjVri4I30" 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>You can follow the original tutorial to build this app <a target="_blank" href="https://www.freecodecamp.org/news/build-a-full-stack-mevn-app/">here</a>.</p>
<p>Happy coding!</p>
<p>If you enjoyed this article, please consider <a target="_blank" href="https://www.nightpathpub.com/">checking out my games and books</a>, <a target="_blank" href="https://www.youtube.com/msfarzan?sub_confirmation=1">subscribing to my YouTube channel</a>, or <a target="_blank" href="https://discord.gg/RF6k3nB">joining the <em>Entromancy</em> Discord</a>.</p>
<p>M. S. Farzan, Ph.D. has written and worked for high-profile video game companies and editorial websites such as Electronic Arts, Perfect World Entertainment, Modus Games, and MMORPG.com, and has served as the Community Manager for games like <em>Dungeons &amp; Dragons Neverwinter</em> and <em>Mass Effect: Andromeda</em>. He is the Creative Director and Lead Game Designer of <em><a target="_blank" href="https://www.nightpathpub.com/rpg">Entromancy: A Cyberpunk Fantasy RPG</a></em> and author of <em><a target="_blank" href="http://nightpathpub.com/books">The Nightpath Trilogy</a></em>. Find M. S. Farzan on Twitter <a target="_blank" href="https://twitter.com/sominator">@sominator</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Redis to Supercharge Your Web APIs ]]>
                </title>
                <description>
                    <![CDATA[ By Tarique Ejaz Performance is an essential parameter to consider when you're designing any piece of software. It is particularly important when it comes to what happens behind-the-scenes.  We, as developers and technologists, adopt multiple tweaks a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/redis-caching-essentials-with-node-and-mongoose/</link>
                <guid isPermaLink="false">66d46150d14641365a050977</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redis ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 13 May 2020 03:50:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/adobe-spark-post--1--1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Tarique Ejaz</p>
<p>Performance is an essential parameter to consider when you're designing any piece of software. It is particularly important when it comes to what happens behind-the-scenes. </p>
<p>We, as developers and technologists, adopt multiple tweaks and implementations in order to improve performance. This is where caching comes into play. </p>
<blockquote>
<p>Caching is defined as a mechanism to store data or files in a temporary storage location from where it can be instantly accessed whenever required. </p>
</blockquote>
<p>Caching has become a must have in web applications nowadays. We can use Redis to supercharge our web APIs - which are built using Node.js and MongoDB.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/redis.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>"Caching would apparently still play a super important role 100 to 200 years down the line."</em></p>
<h2 id="heading-redis-a-laymans-overview">Redis: A Layman's Overview</h2>
<p><a target="_blank" href="https://redis.io/">Redis</a>, according to the official documentation, is defined as an in-memory data structure store which is used as a database, message broker, or cache storage. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. </p>
<p>Okay, that is quite a lot of data structures right there. Just to make it simple, almost all the data structures supported can be condensed into one form of string or the other. You will get more clarity as we run through the implementation.</p>
<p>But one thing is clear. Redis is powerful, and when used properly can make our applications not only faster but amazingly efficient. Enough talk. Let's get our hands dirty.</p>
<h2 id="heading-lets-talk-code">Let's Talk Code</h2>
<p>Before we start off, you will need to get redis setup in your local system. You can follow this <a target="_blank" href="https://redis.io/topics/quickstart">quick setup</a> process to get redis up and running. </p>
<p>Done? Cool. Let's start. We have a simple application created in Express which makes use of an instance in MongoDB Atlas to read and write data from. </p>
<p>We have two major APIs created in the <code>/blogs</code> route file.</p>
<pre><code class="lang-js">...

<span class="hljs-comment">// GET - Fetches all blog posts for required user</span>
blogsRouter.route(<span class="hljs-string">'/:user'</span>)
    .get(<span class="hljs-keyword">async</span> (req, res, next) =&gt; {
        <span class="hljs-keyword">const</span> blogs = <span class="hljs-keyword">await</span> Blog.find({ <span class="hljs-attr">user</span>: req.params.user });

        res.status(<span class="hljs-number">200</span>).json({
            blogs,
        });
    });

<span class="hljs-comment">// POST - Creates a new blog post</span>
blogsRouter.route(<span class="hljs-string">'/'</span>)
    .post(<span class="hljs-keyword">async</span> (req, res, next) =&gt; {
        <span class="hljs-keyword">const</span> existingBlog = <span class="hljs-keyword">await</span> Blog.findOne({ <span class="hljs-attr">title</span>: req.body.title });

        <span class="hljs-keyword">if</span> (!existingBlog) {
            <span class="hljs-keyword">let</span> newBlog = <span class="hljs-keyword">new</span> Blog(req.body);

            <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> newBlog.save();

            <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json({
                <span class="hljs-attr">message</span>: <span class="hljs-string">`Blog <span class="hljs-subst">${result.id}</span> is successfully created`</span>,
                result,
            });
        }

        res.status(<span class="hljs-number">200</span>).json({
            <span class="hljs-attr">message</span>: <span class="hljs-string">'Blog with same title exists'</span>,
        });
    });

...
</code></pre>
<h3 id="heading-sprinkling-some-redis-goodness">Sprinkling Some Redis Goodness</h3>
<p>We start off by downloading the npm package <a target="_blank" href="https://www.npmjs.com/package/redis"><code>redis</code></a> to connect to the local redis server. </p>
<pre><code class="lang-js"><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> redis = <span class="hljs-built_in">require</span>(<span class="hljs-string">'redis'</span>);
<span class="hljs-keyword">const</span> util = <span class="hljs-built_in">require</span>(<span class="hljs-string">'util'</span>);

<span class="hljs-keyword">const</span> redisUrl = <span class="hljs-string">'redis://127.0.0.1:6379'</span>;
<span class="hljs-keyword">const</span> client = redis.createClient(redisUrl);
client.hget = util.promisify(client.hget);

...
</code></pre>
<p>We make use of the <code>utils.promisify</code> function to transform the <code>client.hget</code> function to return a promise instead of a callback. You can read more about <code>promisification</code> <a target="_blank" href="https://javascript.info/promisify">here</a>.</p>
<p>The Redis connection is in place. Before we start writing any more caching code, let us take a step back and try to understand what are the requirements we need to fulfill and the likely challenges we might face. </p>
<p>Our caching strategy should be able to address the following points.</p>
<ul>
<li>Cache the request for all blog posts for a particular user</li>
<li><p>Clear cache every time a new blog post is created</p>
<p>The likely challenges we should be careful of as we go about our strategy are:</p>
</li>
<li><p>The right way to handle key creation for storing cache data</p>
</li>
<li>Cache expiration logic and forced expiration for maintaining cache freshness</li>
<li>Reusable implementation of caching logic</li>
</ul>
<p>All right. We have our points jotted down and redis connected. On to the next step.</p>
<h3 id="heading-overriding-the-default-mongoose-exec-function">Overriding the Default Mongoose Exec Function</h3>
<p>We want our caching logic to be reusable. And not only reusable, we also want it to be the first checkpoint before we make any query to the database. This can easily be done by using a simple hack of piggy-backing onto the mongoose exec function.</p>
<pre><code class="lang-js">...

const exec = mongoose.Query.prototype.exec;

...

mongoose.Query.prototype.exec = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    ...

     const result = <span class="hljs-keyword">await</span> exec.apply(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>);

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Data Source: Database'</span>);
    <span class="hljs-keyword">return</span> result;
}

...
</code></pre>
<p>We make use of the prototype object of mongoose to add our caching logic code as the first execution in the query.</p>
<h3 id="heading-adding-cache-as-a-query">Adding Cache as a Query</h3>
<p>In order to denote which queries should be up for caching, we create a mongoose query. We provide the ability to pass the <code>user</code> to be used as a hash-key through the <code>options</code> object. </p>
<blockquote>
<p><strong>Note:</strong> Hashkey serves as an identifier for a hash data structure which, in layman terms, can be stated as the parent key to a set of key-value pairs. Thereby, enabling caching of a larger number of query-value set. You can read more about hashes in redis <a target="_blank" href="https://redislabs.com/ebook/part-1-getting-started/chapter-1-getting-to-know-redis/1-2-what-redis-data-structures-look-like/1-2-4-hashes-in-redis/">here</a>.</p>
</blockquote>
<pre><code class="lang-js">...

mongoose.Query.prototype.cache = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options = {}</span>) </span>{
    <span class="hljs-built_in">this</span>.enableCache = <span class="hljs-literal">true</span>;
    <span class="hljs-built_in">this</span>.hashKey = <span class="hljs-built_in">JSON</span>.stringify(options.key || <span class="hljs-string">'default'</span>);

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

...
</code></pre>
<p>Having done so, we can easily use the <code>cache(&lt;options argument&gt;)</code> query along with the queries we want to cache in the following manner.</p>
<pre><code class="lang-js">...

const blogs = <span class="hljs-keyword">await</span> Blog
                    .find({ <span class="hljs-attr">user</span>: req.params.user })
                    .cache({ <span class="hljs-attr">key</span>: req.params.user });

...
</code></pre>
<h3 id="heading-crafting-the-cache-logic">Crafting The Cache Logic</h3>
<p>We have set up a common reusable query to denote which queries need to be cached. Let's go ahead and write the central caching logic.</p>
<pre><code class="lang-js">...

mongoose.Query.prototype.exec = <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.enableCache) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Data Source: Database'</span>);
        <span class="hljs-keyword">return</span> exec.apply(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>);
    }

    <span class="hljs-keyword">const</span> key = <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">Object</span>.assign({}, <span class="hljs-built_in">this</span>.getQuery(), {
        <span class="hljs-attr">collection</span>: <span class="hljs-built_in">this</span>.mongooseCollection.name,
    }));

    <span class="hljs-keyword">const</span> cachedValue = <span class="hljs-keyword">await</span> client.hget(<span class="hljs-built_in">this</span>.hashKey, key);

    <span class="hljs-keyword">if</span> (cachedValue) {
        <span class="hljs-keyword">const</span> parsedCache = <span class="hljs-built_in">JSON</span>.parse(cachedValue);

        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Data Source: Cache'</span>);

        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Array</span>.isArray(parsedCache) 
                ?  parsedCache.map(<span class="hljs-function"><span class="hljs-params">doc</span> =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">this</span>.model(doc)) 
                :  <span class="hljs-keyword">new</span> <span class="hljs-built_in">this</span>.model(parsedCache);
    }

    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> exec.apply(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>);

    client.hmset(<span class="hljs-built_in">this</span>.hashKey, key, <span class="hljs-built_in">JSON</span>.stringify(result), <span class="hljs-string">'EX'</span>, <span class="hljs-number">300</span>);

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Data Source: Database'</span>);
    <span class="hljs-keyword">return</span> result;
};

...
</code></pre>
<p>Whenever we use the <code>cache()</code> query along with our main query, we set the <code>enableCache</code> key to be true. </p>
<p>If the key is false, we return the main <code>exec</code> query as default. If not, we first form the key for fetching and storing/refreshing the cache data. </p>
<p>We use the <code>collection</code> name along with the default query as the key name for the sake of uniqueness. The hash-key used is the name of the <code>user</code> which we have already set earlier in the <code>cache()</code> function definition. </p>
<p>The cached data is fetched using the <code>client.hget()</code> function which requires the hash-key and the consequent key as parameters. </p>
<blockquote>
<p><strong>Note:</strong> We always use <code>JSON.parse()</code> while fetching any data from redis. And similarly, we use <code>JSON.stringify()</code> on the key and data before storing anything into redis. This is done since redis does not support JSON data structures.</p>
</blockquote>
<p>Once we have obtained the cached data, we have to transform each of the cached objects into a mongoose model. This can be done by simply using <code>new this.model(&lt;object&gt;)</code>. </p>
<p>If the cache does not contain the required data, we make a query to the database. Then, having returned the data to the API, we refresh the cache using <code>client.hmset()</code>. We also set a default cache expiration time of 300 seconds. This is customizable based on your caching strategy.</p>
<p>The caching logic is in place. We have also set a default expiration time. Next up, we look at forcing cache expiration whenever a new blog post is created.</p>
<h3 id="heading-forced-cache-expiration">Forced Cache Expiration</h3>
<p>In certain cases, such as when a user creates a new blog post, the user expects that the new post should be available when they fetche all the posts. </p>
<p>In order to do so, we have to clear the cache related to that user and update it with new data. So we have to force expiration. We can do that by invoking the <code>del()</code> function provided by redis. </p>
<pre><code class="lang-js">...

module.exports = {
    clearCache(hashKey) {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Cache cleaned'</span>);
        client.del(<span class="hljs-built_in">JSON</span>.stringify(hashKey));
    }
}

...
</code></pre>
<p>We also have to keep in mind that we will be forcing expiration on multiple routes. One extensible way is to use this <code>clearCache()</code> as a middleware and call it once any query related to a route has finished execution. </p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { clearCache } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../services/cache'</span>);

<span class="hljs-built_in">module</span>.exports = <span class="hljs-keyword">async</span> (req, res, next) =&gt; {
    <span class="hljs-comment">// wait for route handler to finish running</span>
    <span class="hljs-keyword">await</span> next(); 

    clearCache(req.body.user);
}
</code></pre>
<p>This middleware can be easily called on a particular route in the following way.</p>
<pre><code class="lang-js">...

blogsRouter.route(<span class="hljs-string">'/'</span>)
    .post(cleanCache, <span class="hljs-keyword">async</span> (req, res, next) =&gt; {

    ...

    }

...
</code></pre>
<p>And we are done. I agree that was a quite a lot of code. But with that last part, we have set up redis with our application and taken care of almost all the likely challenges. It is time to see our caching strategy in action.</p>
<h2 id="heading-redis-in-action">Redis in Action</h2>
<p>We make use of <a target="_blank" href="https://www.postman.com/">Postman</a> as the API client to see our caching strategy in action. Here we go. Let's run through the API operations, one by one.</p>
<ol>
<li>We create a new blog post using the <code>/blogs</code> route</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/Screenshot--50-.png" alt="Image" width="600" height="400" loading="lazy">
<em>New Blog Post Creation</em></p>
<ol start="2">
<li>We then fetch all the blog posts related to user <code>tejaz</code></li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/Screenshot--51-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Fetching all Blog Posts for User tejaz</em></p>
<ol start="3">
<li>We fetch all the blog posts for user <code>tejaz</code> once more.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/Screenshot--52-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Fetch all Blog Posts for User tejaz Once More</em></p>
<p>You can clearly see that when we fetch from the cache, the time taken has gone down from <strong>409ms</strong> to <strong>24ms</strong>. This supercharges your API by decreasing the time taken by almost <strong>95%.</strong> </p>
<p>Plus, we can clearly see that cache expiration and update operations work as expected.</p>
<p>You can find the complete source code in the <code>redis-express</code> folder here.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/tarique93102/article-snippets/tree/master/redis-express">https://github.com/tarique93102/article-snippets/tree/master/redis-express</a></div>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Caching is a mandatory step for any performance-efficient and data-intensive application. Redis helps you easily achieve this in your web applications. It is a super powerful tool, and if used properly it can definitely provide an excellent experience to developers as well as users all around.</p>
<p>You can find the complete set of redis commands <a target="_blank" href="https://redis.io/commands">here</a>. You can use it with <code>redis-cli</code> to monitor your cache data and application processes. </p>
<p>The possibilities offered by any particular technology is truly endless. If you have any queries, you can reach out to me on <code>[LinkedIn](https://www.linkedin.com/in/tarique-ejaz/)</code>. </p>
<p>In the mean time, keep coding.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Three Things to Consider Before Deploying Your First Full Stack App ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan Building a full stack app is no small endeavor, and deploying it comes with its own host of things to consider. I'm a tabletop game developer, and recently deployed a simple roleplaying game tracker that uses the M-E-V-N stack (you ca... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/3-things-to-consider-before-deploying-your-first-full-stack-app/</link>
                <guid isPermaLink="false">66d851dd836d1162d8815c3c</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ containers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Heroku ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 17 Mar 2020 21:12:22 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9c1d740569d1a4ca3007.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>Building a full stack app is no small endeavor, and deploying it comes with its own host of things to consider.</p>
<p>I'm a <a target="_blank" href="https://www.nightpathpub.com/entromancy">tabletop game</a> developer, and recently deployed a simple <a target="_blank" href="https://mevn-rpg-app.herokuapp.com/">roleplaying game tracker</a> that uses the <a target="_blank" href="https://www.mongodb.com/">M</a>-<a target="_blank" href="https://expressjs.com/">E</a>-<a target="_blank" href="https://vuejs.org/">V</a>-<a target="_blank" href="https://nodejs.org/en/">N</a> stack (you can follow my tutorial to create your own app <a target="_blank" href="https://www.freecodecamp.org/news/build-a-full-stack-mevn-app/">here</a>).  </p>
<p>In deploying the app, I came across three key takeaways that may be useful as you begin considering the best way to bring your projects from development to production. </p>
<p>You can check out the code to my app on <a target="_blank" href="https://github.com/sominator/mevn-rpg-app">GitHub</a>, and I should mention that it includes Chad Carteret's <a target="_blank" href="https://codepen.io/retractedhack/pen/gPLpWe">very cool CSS statblock</a> in prettifying what's otherwise very basic HTML.</p>
<p>If you're thinking of following the same path to deployment as I have here, be sure to check out the official documentation on <a target="_blank" href="https://devcenter.heroku.com/articles/deploying-nodejs">Heroku</a>, the <a target="_blank" href="https://cli.vuejs.org/guide/deployment.html">Vue CLI</a>, and <a target="_blank" href="https://medium.com/netscape/deploying-a-vue-js-2-x-app-to-heroku-in-5-steps-tutorial-a69845ace489">this tutorial</a> by Nick Manning.</p>
<p>You'll also want to take a look at Will Abramson's <a target="_blank" href="https://www.freecodecamp.org/news/lessons-learned-from-deploying-my-first-full-stack-web-application-34f94ec0a286/">article on a similar topic</a>.</p>
<p>On to deployment!</p>
<h2 id="heading-your-front-end-and-back-end-can-be-deployed-together-or-separately-depending-on-your-apps-complexity">Your front end and back end can be deployed together or separately, depending on your app's complexity.</h2>
<p>One snag that seems to appear immediately when considering production is the structural question of how to deploy the front and back ends of your app.</p>
<p>Should the client (or static files) live in the same place as the server and database? Or should they be separate, with the front end making HTTP requests from elsewhere to the back end using <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">CORS</a>?</p>
<p>The answer is yes! Or no. Maybe??</p>
<p>For better or worse, there's no one-size-fits-all solution to this question, as it will likely depend on your app's architecture and complexity. In the roleplaying game tracker that I linked to above, I have the whole stack running on a single Heroku <a target="_blank" href="https://www.heroku.com/dynos">dyno</a>, with the following folder structure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Folder-Structure.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>All of the front and back end files live in the same place, with the Vue client built for production in a folder located at /client/dist.</p>
<p>In server.js, along with a bunch of database and routing code, there's a little line that says:</p>
<pre><code class="lang-javascript">server.use(serveStatic(__dirname + <span class="hljs-string">"/client/dist"</span>));
</code></pre>
<p>In Express, this tells the app to serve my static client files from a particular folder, and enables me to run the front and back ends all within the same environment. If you're deploying a similarly simple app, this type of solution might work for you as well.  </p>
<p>Conversely, and depending on your project's complexity, you may have to separate the front and back ends and treat them as separate applications, which is no big deal. In the app above, my client is making calls to static API endpoints that are handled by the server, like this:</p>
<pre><code class="lang-javascript">getQuests: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    axios
        .get(<span class="hljs-string">'https://mevn-rpg-app.herokuapp.com/quests'</span>)
        .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> (<span class="hljs-built_in">this</span>.questData = response.data))                   
 }
</code></pre>
<p>Technically, my client could be making those requests from anywhere - even a static GitHub Pages site. This type of solution can help separate your app into two distinct entities to tackle, which is sometimes better than trying to cram the whole project into one location.</p>
<p>One note: if you're going to be making cross-origin HTTP requests - that is, requests from a client that lives on a separate domain from the API or server - you'll need to become familiar with <a target="_blank" href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing">CORS</a>.  You can read more about it in <a target="_blank" href="https://www.freecodecamp.org/news/i-built-a-web-api-with-express-flask-aspnet/">this article</a>.  </p>
<h2 id="heading-your-code-will-need-to-change-to-support-a-production-environment">Your code will need to change to support a production environment.</h2>
<p>When you're knee deep in the development process, it can be easy to lose track of how much of your code depends on local files or other data.</p>
<p>Consider the following in a locally-running server.js:</p>
<pre><code class="lang-javascript">server.listen(<span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Server started!"</span>));
</code></pre>
<p>On a local machine, the code just asks the server to listen on port 3000 and log to the console that we're ready for liftoff.</p>
<p>In a production environment, the server has no concept of where the "localhost" should be, or to whose port 3000 it should be listening. With this example, you'd have to change your code to something like:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">3000</span>;

server.listen(port, <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Server started!"</span>));
</code></pre>
<p>The above instructs the server to instead listen at port 3000 of the <em>process</em> that's currently running, wherever that might be (check out <a target="_blank" href="https://codeburst.io/process-env-what-it-is-and-why-when-how-to-use-it-effectively-505d0b2831e7">this article</a> for further reading on this topic).</p>
<p>Similarly, in my app, I have several modules that need to be imported by one another to function:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Folder-Structure-Expanded.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In /routes/Quests.js, for example, I have a router that tells the server what to do when receiving API requests to interact with quest-related items in the database. The router needs to import a <a target="_blank" href="https://mongoosejs.com/docs/guide.html">Mongoose schema</a> from /models/quest.js to function properly. If the application were running locally, we could just say:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Quest = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/quest'</span>);
</code></pre>
<p>Pretty simple! Yet, unfortunately, our server won't know where to find the root directory of our project once deployed. In Express, we'd change our code to something like:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>);
<span class="hljs-keyword">const</span> Quest = <span class="hljs-built_in">require</span>(path.join(__dirname, <span class="hljs-string">'../models/quest'</span>));
</code></pre>
<p>Your particular case might be different, depending on your language and framework(s), but you'll need to get specific about what your code looks like in a production environment rather than in your local development environment.</p>
<p>Additionally, you're probably already familiar with whatever bundler you're using for your front end (e.g., <a target="_blank" href="https://webpack.js.org/">webpack</a>), and will want to build your client for production to optimize it for deployment.</p>
<h2 id="heading-you-have-a-multitude-of-deployment-platforms-from-which-to-choose">You have a multitude of deployment platforms from which to choose.</h2>
<p>If you've deployed a front end website or some other type of static app, you might be familiar with just pushing your files to some remote repository and calling it a day.</p>
<p>Deploying a full stack app (or even just a back end) is eminently more complex. You'll need a dedicated server, or something that emulates one, to respond to the HTTP requests that it will be receiving and work with an online database.</p>
<p>There are a number of services that will do this very thing for you, and the spectrum ranges based on price, scalability, complexity, and other factors.</p>
<p>There's a bunch of articles out there that compare <a target="_blank" href="https://en.wikipedia.org/wiki/Platform_as_a_service">PaaS</a> options for deployment, but here are some thoughts as you consider platforms for your first project:</p>
<ul>
    <li><strong>Heroku</strong>: If you have a small project like mine or just want to learn about deployment, a good first step could be <a href="https://www.heroku.com/">Heroku</a>.</li>
    <li><strong>AWS, Docker, and Kubernetes</strong>: If you're seeking a career in full stack web development or DevOps, now's a good time to familiarize yourself with <a href="https://aws.amazon.com/">Amazon Web Services</a> and/or container platforms like <a href="https://www.docker.com/">Docker</a> and <a href="https://kubernetes.io/">Kubernetes</a>.</li>
    <li><strong>Azure</strong>: If you're a C# or .NET developer, <a href="https://azure.microsoft.com/en-us/">Azure</a> appears to be a seamless way to deploy your apps without having to leave the safety of the Microsoft ecosystem.</li>
</ul>

<p>There are, of course, several other options out there, and your particular use-case scenario might depend on pricing or the specific feature sets that are on offer.</p>
<p>Additionally, you'll want to consider any addons that will be necessary to replicate your app's functionality in a production environment. My roleplaying game tracker, for example, uses MongoDB, but the production version certainly can't use the little database on my local machine! Instead, I've used the <a target="_blank" href="https://elements.heroku.com/addons/mongolab">mLab</a> Heroku addon to get the live site up and running with the same functionality as in my development environment.</p>
<p>Your app's success, as well as your own progress as a full stack web developer, depend on your ability to consider deployment options and create a successful pipeline for production. With a little research, I'm certain that you can find the best solution that fits all of your app's needs.</p>
<p>Happy coding!</p>
<p>If you enjoyed this article, please consider <a target="_blank" href="https://www.nightpathpub.com/">checking out my games and books</a>, <a target="_blank" href="https://www.youtube.com/msfarzan?sub_confirmation=1">subscribing to my YouTube channel</a>, or <a target="_blank" href="https://discord.gg/RF6k3nB">joining the <em>Entromancy</em> Discord</a>.</p>
<p>M. S. Farzan, Ph.D. has written and worked for high-profile video game companies and editorial websites such as Electronic Arts, Perfect World Entertainment, Modus Games, and MMORPG.com, and has served as the Community Manager for games like <em>Dungeons &amp; Dragons Neverwinter</em> and <em>Mass Effect: Andromeda</em>. He is the Creative Director and Lead Game Designer of <em><a target="_blank" href="https://www.nightpathpub.com/rpg">Entromancy: A Cyberpunk Fantasy RPG</a></em> and author of <em><a target="_blank" href="http://nightpathpub.com/books">The Nightpath Trilogy</a></em>. Find M. S. Farzan on Twitter <a target="_blank" href="https://twitter.com/sominator">@sominator</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Full Stack RPG Character Generator with MongoDB, Express, Vue, and Node (the MEVN Stack) ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan I'm a tabletop game developer, and enjoy making apps that have the potential to perform some service related to gaming. In this article, we'll walk through the steps to create a roleplaying game character generator using MongoDB, Expr... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-full-stack-mevn-app/</link>
                <guid isPermaLink="false">66d851dfe0db794d56c01bf3</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Back end development  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 09 Mar 2020 18:50:41 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9c3a740569d1a4ca30ca.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>I'm a <a target="_blank" href="https://www.nightpathpub.com/">tabletop game</a> developer, and enjoy making apps that have the potential to perform some service related to gaming. In this article, we'll walk through the steps to create a roleplaying game character generator using <a target="_blank" href="https://www.mongodb.com/">MongoDB</a>, <a target="_blank" href="https://expressjs.com/">Express</a>, <a target="_blank" href="http://vuejs.org/">Vue</a>, and <a target="_blank" href="https://nodejs.org/en/">Node</a> (also known as the "MEVN" stack). </p>
<p>Prerequisites: this tutorial presumes that you have Node/<a target="_blank" href="https://www.npmjs.com/">NPM</a> and MongoDB installed and configured, with a code editor and <a target="_blank" href="https://en.wikipedia.org/wiki/Command-line_interface">CLI</a> (or <a target="_blank" href="https://www.freecodecamp.org/news/how-to-set-up-an-integrated-development-environment-ide/">IDE</a>) ready to go.</p>
<p>If you'd prefer to follow along with a visual tutorial, you can check out the companion video to this article below:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/i5XUgda08qk" 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>I should also mention that this tutorial would not have been possible without Bennett Dungan's article on <a target="_blank" href="https://dev.to/beznet/build-a-rest-api-with-node-express-mongodb-4ho4">building a REST API</a>, Aneeta Sharma's tutorial on <a target="_blank" href="https://medium.com/@anaida07/mevn-stack-application-part-1-3a27b61dcae0">full stack MEVN web apps</a>, and Matt Maribojoc's article on <a target="_blank" href="https://medium.com/@mattmaribojoc/creating-a-todo-app-with-a-mevn-full-stack-part-1-da0f4df7e15">the same topic</a>.  </p>
<p>I used each of these articles in addition to official documentation (for <a target="_blank" href="https://vuejs.org/v2/guide/">Vue</a>, <a target="_blank" href="https://expressjs.com/en/starter/installing.html">Express</a>, and a whole lot more) in learning to create my own MEVN apps (you can read more about my journey with web APIs <a target="_blank" href="https://www.freecodecamp.org/news/i-built-a-web-api-with-express-flask-aspnet/">here</a>). </p>
<p>You can access the entire repository for this tutorial on <a target="_blank" href="https://github.com/sominator/mevn-character-generator">GitHub</a>.</p>
<h2 id="heading-the-front-end">The Front End</h2>
<p>Our app is going to allow us to create new roleplaying game characters and view them altogether, with the following stack:</p>
<ul>
    <li>Vue Client</li>
    <li>Node/Express Server</li>
    <li>MongoDB Database</li>
</ul>

<p>The Vue Client will make <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">HTTP requests</a> to the Node/Express Server (or "<a target="_blank" href="https://en.wikipedia.org/wiki/Application_programming_interface">API</a>"), which will in turn communicate with our MongoDB Database to send data back up the stack.</p>
<p>We'll begin by opening a command line, creating a new directory for our project, and navigating into that directory:</p>
<pre><code class="lang-cli">mkdir mevn-character-generator
cd mevn-character-generator
</code></pre>
<p>We'll then install the <a target="_blank" href="https://cli.vuejs.org/">Vue CLI</a> globally to help us scaffold a basic app: </p>
<pre><code class="lang-cli">npm install -g @vue/cli
</code></pre>
<p>Next, we'll use the Vue CLI to create a new app called "Client" within our mevn-character-generator directory:</p>
<pre><code class="lang-cli">vue create client
</code></pre>
<p>You can just hit "enter" at the prompt to keep going.</p>
<p>We can run our app by first navigating into the /client folder:</p>
<pre><code class="lang-cli">cd client
npm run serve
</code></pre>
<p>When the script has completed running, we can now open a browser page and navigate to the URL indicated by our terminal (usually http://localhost:8080 or 8081).  We should see something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Vue-Template.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Nice! The Vue CLI has scaffolded a basic app for us, and is rendering it right into the browser. It'll also reload the page automatically upon file changes, and throw errors if something in the code looks amiss.</p>
<p>Let's open the project directory in our code editor to take a look at the file structure, which should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Client-Directory.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you're OCD like I am, you can go ahead and delete the "favicon.ico" file and "/assets" folder as we won't need them for this project.</p>
<p>Diving into /src/main.js, we see:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.vue'</span>

Vue.config.productionTip = <span class="hljs-literal">false</span>

<span class="hljs-keyword">new</span> Vue({
  <span class="hljs-attr">render</span>: <span class="hljs-function"><span class="hljs-params">h</span> =&gt;</span> h(App),
}).$mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<p>This file is the main entry point for our client. It tells the browser to mount our App.vue file to the div with id "#app" in /public/index.html.</p>
<p>Let's look at /src/App.vue (I've omitted some code for readability):</p>
<pre><code class="lang-javascript">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Vue logo"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./assets/logo.png"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">HelloWorld</span> <span class="hljs-attr">msg</span>=<span class="hljs-string">"Welcome to Your Vue.js App"</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">template</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> HelloWorld <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/HelloWorld.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'App'</span>,
  <span class="hljs-attr">components</span>: {
    HelloWorld
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span>
#app {
...
}
<span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>App.vue is a typical Vue <a target="_blank" href="https://vuejs.org/v2/guide/components.html">component</a>, with , </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Mongoose 101: An Introduction to the Basics, Subdocuments, and Population ]]>
                </title>
                <description>
                    <![CDATA[ Mongoose is a library that makes MongoDB easier to use. It does two things: It gives structure to MongoDB Collections It gives you helpful methods to use In this article, we'll go through:  The basics of using Mongoose  Mongoose subdocuments Mongo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/mongoose101/</link>
                <guid isPermaLink="false">66c4c794d788a9c53d88d2f1</guid>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Zell Liew ]]>
                </dc:creator>
                <pubDate>Wed, 22 Jan 2020 14:00:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9d9f740569d1a4ca38bb.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Mongoose is a library that makes MongoDB easier to use. It does two things:</p>
<ol>
<li>It gives structure to MongoDB Collections</li>
<li>It gives you helpful methods to use</li>
</ol>
<p>In this article, we'll go through: </p>
<ol>
<li>The basics of using Mongoose </li>
<li>Mongoose subdocuments</li>
<li>Mongoose population</li>
</ol>
<p>By the end of the article, you should be able to use Mongoose without problems.  </p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>I assume you have done the following:</p>
<ol>
<li>You have installed MongoDB on your computer</li>
<li>You know how to set up a local MongoDB connection</li>
<li>You know how to see the data you have in your database</li>
<li>You know what "collections" are in MongoDB</li>
</ol>
<p>If you don't know any of these, please read <a target="_blank" href="https://zellwk.com/blog/local-mongodb">"How to set up a local MongoDB connection"</a> before you continue.</p>
<p>I also assume you know how to use MongoDB to create a simple CRUD app. If you don't know how to do this, please read <a target="_blank" href="https://zellwk.com/blog/crud-express-mongodb">"How to build a CRUD app with Node, Express, and MongoDB"</a> before you continue.</p>
<h2 id="heading-mongoose-basics">Mongoose Basics</h2>
<p>Here, you'll learn how to: </p>
<ol>
<li>Connect to the database</li>
<li>Create a Model</li>
<li>Create a Document</li>
<li>Find a Document</li>
<li>Update a Document</li>
<li>Delete a Document</li>
</ol>
<h3 id="heading-connecting-to-a-database">Connecting to a database</h3>
<p>First, you need to download Mongoose.</p>
<pre><code class="lang-bash">npm install mongoose --save
</code></pre>
<p>You can connect to a database with the <code>connect</code> method. Let's say we want to connect to a database called <code>street-fighters</code>. Here's the code you need:</p>
<pre><code class="lang-js"><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> url = <span class="hljs-string">'mongodb://127.0.0.1:27017/street-fighters'</span>

mongoose.connect(url, { <span class="hljs-attr">useNewUrlParser</span>: <span class="hljs-literal">true</span> })
</code></pre>
<p>We want to know whether our connection has succeeded or failed. This helps us with debugging.</p>
<p>To check whether the connection has succeeded, we can use the <code>open</code> event. To check whether the connection failed, we use the <code>error</code> event.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> db = mongoose.connection
db.once(<span class="hljs-string">'open'</span>, <span class="hljs-function"><span class="hljs-params">_</span> =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Database connected:'</span>, url)
})

db.on(<span class="hljs-string">'error'</span>, <span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
  <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'connection error:'</span>, err)
})
</code></pre>
<p>Try connecting to the database. You should see a log like this:</p>
<p><img src="https://zellwk.com/images/2019/mongoose/connect-database.png" alt="Connected to a database." width="600" height="400" loading="lazy"></p>
<h3 id="heading-creating-a-model">Creating a Model</h3>
<p>In Mongoose, you need to <strong>use models to create, read, update, or delete items</strong> from a MongoDB collection.</p>
<p>To create a Model, <strong>you need to create a Schema</strong>. A Schema lets you <strong>define the structure of an entry</strong> in the collection. This entry is also called a document.</p>
<p>Here's how you create a schema:</p>
<pre><code class="lang-js"><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> Schema = mongoose.Schema

<span class="hljs-keyword">const</span> schema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-comment">// ...</span>
})
</code></pre>
<p>You can use <a target="_blank" href="https://mongoosejs.com/docs/guide.html">10 different kinds of values</a> in a Schema. Most of the time, you'll use these six:</p>
<ul>
<li>String</li>
<li>Number</li>
<li>Boolean</li>
<li>Array</li>
<li>Date</li>
<li>ObjectId</li>
</ul>
<p>Let's put this into practice.</p>
<p>Say we want to create characters for our Street Fighter database.</p>
<p>In Mongoose, it's a normal practice to <strong>put each model in its own file.</strong> So we will create a <code>Character.js</code> file first. This <code>Character.js</code> file will be placed in the <code>models</code> folder.</p>
<pre><code class="lang-bash">project/
    |- models/
        |- Character.js
</code></pre>
<p>In <code>Character.js</code>, we create a <code>characterSchema</code>.</p>
<pre><code class="lang-js"><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> Schema = mongoose.Schema

<span class="hljs-keyword">const</span> characterSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-comment">// ...</span>
})
</code></pre>
<p>Let's say we want to save two things into the database:</p>
<ol>
<li>Name of the character</li>
<li>Name of their ultimate move</li>
</ol>
<p>Both can be represented with Strings.</p>
<pre><code class="lang-js"><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> Schema = mongoose.Schema

<span class="hljs-keyword">const</span> characterSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">ultimate</span>: <span class="hljs-built_in">String</span>
})
</code></pre>
<p>Once we've created <code>characterSchema</code>, we can use mongoose's <code>model</code> method to create the model.</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'Character'</span>, characterSchema)
</code></pre>
<h3 id="heading-creating-a-document">Creating a document</h3>
<p>Let's say you have a file called <code>index.js</code>. This is where we'll perform Mongoose operations for this tutorial.</p>
<pre><code class="lang-bash">project/
    |- index.js
    |- models/
        |- Character.js
</code></pre>
<p>First, you need to load the Character model. You can do this with <code>require</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> Character = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./models/Character'</span>)
</code></pre>
<p>Let's say you want to create a character called Ryu. Ryu has an ultimate move called "Shinku Hadoken".</p>
<p>To create Ryu, you use the <code>new</code>, followed by your model. In this case, it's <code>new Character</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">new</span> Character ({
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span>,
  <span class="hljs-attr">ultimate</span>: <span class="hljs-string">'Shinku Hadoken'</span>
})
</code></pre>
<p><code>new Character</code> creates the character in memory. It has not been saved to the database yet. <strong>To save to the database, you can run the <code>save</code> method</strong>.</p>
<pre><code class="lang-js">ryu.save(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">error, document</span>) </span>{
  <span class="hljs-keyword">if</span> (error) <span class="hljs-built_in">console</span>.error(error)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">document</span>)
})
</code></pre>
<p>If you run the code above, you should see this in the console.</p>
<figure><img src="https://zellwk.com/images/2019/mongoose/saved.png" alt="Ryu saved to the database." width="600" height="400" loading="lazy"></figure>

<h4 id="heading-promises-and-asyncawait">Promises and Async/await</h4>
<p><strong>Mongoose supports promises.</strong> It lets you write nicer code like this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// This does the same thing as above</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">saveCharacter</span> (<span class="hljs-params">character</span>) </span>{
  <span class="hljs-keyword">const</span> c = <span class="hljs-keyword">new</span> Character(character)
  <span class="hljs-keyword">return</span> c.save()
}

saveCharacter({
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span>,
  <span class="hljs-attr">ultimate</span>: <span class="hljs-string">'Shinku Hadoken'</span>
})
  .then(<span class="hljs-function"><span class="hljs-params">doc</span> =&gt;</span> { <span class="hljs-built_in">console</span>.log(doc) })
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> { <span class="hljs-built_in">console</span>.error(error) })
</code></pre>
<p>You can also use the <code>await</code> keyword if you have an asynchronous function.</p>
<p>If the Promise or Async/Await code looks foreign to you, I recommend reading <a target="_blank" href="https://zellwk.com/blog/async-await">"JavaScript async and await"</a> before continuing with this tutorial.</p>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">runCode</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">new</span> Character({
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span>,
    <span class="hljs-attr">ultimate</span>: <span class="hljs-string">'Shinku Hadoken'</span>
  })

  <span class="hljs-keyword">const</span> doc = <span class="hljs-keyword">await</span> ryu.save()
  <span class="hljs-built_in">console</span>.log(doc)
}

runCode()
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> { <span class="hljs-built_in">console</span>.error(error) })
</code></pre>
<p>Note: I'll use the async/await format for the rest of the tutorial.</p>
<h4 id="heading-uniqueness">Uniqueness</h4>
<p>Mongoose adds a new character to the database each time you use <code>new Character</code> and <code>save</code>. If you run the code(s) above three times, you'd expect to see three Ryus in the database.</p>
<figure><img src="https://zellwk.com/images/2019/mongoose/three-ryus.png" alt="Three Ryus in the database." width="600" height="400" loading="lazy"></figure>

<p>We don't want to have three Ryus in the database. We want to have <strong>ONE Ryu only</strong>. To do this, we can use the <strong>unique</strong> option.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> characterSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span> },
  <span class="hljs-attr">ultimate</span>: <span class="hljs-built_in">String</span>
})
</code></pre>
<p>The <code>unique</code> option <strong>creates a unique index</strong>. It ensures that we cannot have two documents with the same value (for <code>name</code> in this case).</p>
<p>For <code>unique</code> to work properly, you need to <strong>clear the Characters collection</strong>. To clear the Characters collection, you can use this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">await</span> Character.deleteMany({})
</code></pre>
<p>Try to add two Ryus into the database now. You'll get an <code>E11000 duplicate key error</code>. You won't be able to save the second Ryu.</p>
<figure><img src="https://zellwk.com/images/2019/mongoose/dup-error.png" alt="Duplicated key error." width="600" height="400" loading="lazy"></figure>

<p>Let's add another character into the database before we continue the rest of the tutorial.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ken = <span class="hljs-keyword">new</span> Character({
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Ken'</span>,
  <span class="hljs-attr">ultimate</span>: <span class="hljs-string">'Guren Enjinkyaku'</span>
})

<span class="hljs-keyword">await</span> ken.save()
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose/ryu-ken.png" alt="Database contains two characters." width="600" height="400" loading="lazy"></figure>

<h3 id="heading-finding-a-document">Finding a document</h3>
<p>Mongoose gives you two methods to find stuff from MongoDB.</p>
<ol>
<li><code>findOne</code>: Gets one document.</li>
<li><code>find</code>: Gets an array of documents</li>
</ol>
<h4 id="heading-findone">findOne</h4>
<p><code>findOne</code> <strong>returns the first document</strong> it finds. You can specify any property to search for. Let's search for <code>Ryu</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Character.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
<span class="hljs-built_in">console</span>.log(ryu)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose/found-one.png" alt="Found Ryu from the database." width="600" height="400" loading="lazy"></figure>

<h4 id="heading-find">find</h4>
<p><code>find</code> <strong>returns an array</strong> of documents. If you specify a property to search for, it'll return documents that match your query.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> chars = <span class="hljs-keyword">await</span> Character.find({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
<span class="hljs-built_in">console</span>.log(chars)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose/found-many-ryu.png" alt="Combed through the database and found one character with the name Ryu." width="600" height="400" loading="lazy"></figure>

<p>If you did not specify any properties to search for, it'll return an array that contains all documents in the collection.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> chars = <span class="hljs-keyword">await</span> Character.find()
<span class="hljs-built_in">console</span>.log(chars)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose/found-many.png" alt="Found two characters in the database." width="600" height="400" loading="lazy"></figure>

<h3 id="heading-updating-a-document">Updating a document</h3>
<p>Let's say Ryu has three special moves:</p>
<ol>
<li>Hadoken</li>
<li>Shoryuken</li>
<li>Tatsumaki Senpukyaku</li>
</ol>
<p>We want to add these special moves into the database. First, we need to update our <code>CharacterSchema</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> characterSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span> },
  <span class="hljs-attr">specials</span>: <span class="hljs-built_in">Array</span>,
  <span class="hljs-attr">ultimate</span>: <span class="hljs-built_in">String</span>
})
</code></pre>
<p>Then, we use one of these two ways to update a character:</p>
<ol>
<li>Use <code>findOne</code>, then use <code>save</code></li>
<li>Use <code>findOneAndUpdate</code></li>
</ol>
<h4 id="heading-findone-and-save">findOne and save</h4>
<p>First, we use <code>findOne</code> to get Ryu.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Character.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
<span class="hljs-built_in">console</span>.log(ryu)
</code></pre>
<p>Then, we update Ryu to include his special moves.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Character.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
ryu.specials = [
  <span class="hljs-string">'Hadoken'</span>,
  <span class="hljs-string">'Shoryuken'</span>,
  <span class="hljs-string">'Tatsumaki Senpukyaku'</span>
]
</code></pre>
<p>After we modified <code>ryu</code>, we run <code>save</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Character.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
ryu.specials = [
  <span class="hljs-string">'Hadoken'</span>,
  <span class="hljs-string">'Shoryuken'</span>,
  <span class="hljs-string">'Tatsumaki Senpukyaku'</span>
]

<span class="hljs-keyword">const</span> doc = <span class="hljs-keyword">await</span> ryu.save()
<span class="hljs-built_in">console</span>.log(doc)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose/ryu-updated.png" alt="Updated Ryu." width="600" height="400" loading="lazy"></figure>

<h4 id="heading-findoneandupdate">findOneAndUpdate</h4>
<p><code>findOneAndUpdate</code> is the same as MongoDB's <code>findOneAndModify</code> method.</p>
<p>Here, you search for Ryu and pass the fields you want to update at the same time.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Syntax</span>
<span class="hljs-keyword">await</span> findOneAndUpdate(filter, update)
</code></pre>
<pre><code class="lang-js"><span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">const</span> doc = <span class="hljs-keyword">await</span> Character.findOneAndUpdate(
  { <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> },
  {
    <span class="hljs-attr">specials</span>: [
      <span class="hljs-string">'Hadoken'</span>,
      <span class="hljs-string">'Shoryuken'</span>,
      <span class="hljs-string">'Tatsumaki Senpukyaku'</span>
    ]
  })

<span class="hljs-built_in">console</span>.log(doc)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose/ryu-updated.png" alt="Updated Ryu." width="600" height="400" loading="lazy"></figure>

<h4 id="heading-difference-between-findone-save-vs-findoneandupdate">Difference between findOne + save vs findOneAndUpdate</h4>
<p>Two major differences.</p>
<p>First, the <strong>syntax for <code>findOne` + `save</code> is easier to read</strong> than <code>findOneAndUpdate</code>.</p>
<p>Second, <code>findOneAndUpdate</code> does not trigger the <code>save</code> middleware.</p>
<p><strong>I'll choose <code>findOne</code> + <code>save</code></strong> over <code>findOneAndUpdate</code> anytime because of these two differences.</p>
<h3 id="heading-deleting-a-document">Deleting a document</h3>
<p>There are two ways to delete a character:</p>
<ol>
<li><code>findOne</code> + <code>remove</code></li>
<li><code>findOneAndDelete</code></li>
</ol>
<h4 id="heading-using-findone-remove">Using findOne + remove</h4>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Character.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
<span class="hljs-keyword">const</span> deleted = <span class="hljs-keyword">await</span> ryu.remove()
</code></pre>
<h4 id="heading-using-findoneanddelete">Using findOneAndDelete</h4>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> deleted = <span class="hljs-keyword">await</span> Character.findOneAndDelete({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ken'</span> })
</code></pre>
<h2 id="heading-subdocuments">Subdocuments</h2>
<p>In Mongoose, <strong>subdocuments</strong> are documents that are <strong>nested in other documents</strong>. You can spot a subdocument when a schema is nested in another schema.</p>
<p>Note: MongoDB calls subdocuments <strong>embedded documents</strong>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> childSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span>
});

<span class="hljs-keyword">const</span> parentSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-comment">// Single subdocument</span>
  <span class="hljs-attr">child</span>: childSchema,

  <span class="hljs-comment">// Array of subdocuments</span>
  <span class="hljs-attr">children</span>: [ childSchema ]
});
</code></pre>
<p>In practice, you don't have to create a separate <code>childSchema</code> like the example above. Mongoose helps you create nested schemas when you nest an object in another object.</p>
<pre><code class="lang-js"><span class="hljs-comment">// This code is the same as above</span>
<span class="hljs-keyword">const</span> parentSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-comment">// Single subdocument</span>
  <span class="hljs-attr">child</span>: { <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span> },

  <span class="hljs-comment">// Array of subdocuments</span>
  <span class="hljs-attr">children</span>: [{<span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span> }]
});
</code></pre>
<p>In this section, you will learn to: </p>
<ol>
<li>Create a schema that includes a subdocument</li>
<li>Create documents that contain subdocuments</li>
<li>Update subdocuments that are arrays</li>
<li>Update a single subdocument</li>
</ol>
<h3 id="heading-updating-characterschema">Updating characterSchema</h3>
<p>Let's say we want to create a character called Ryu. Ryu has three special moves.</p>
<ol>
<li>Hadoken</li>
<li>Shinryuken</li>
<li>Tatsumaki Senpukyaku</li>
</ol>
<p>Ryu also has one ultimate move called:</p>
<ol>
<li>Shinku Hadoken</li>
</ol>
<p>We want to save the names of each move. We also want to save the keys required to execute that move.</p>
<p>Here, each move is a subdocument.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> characterSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span> },
  <span class="hljs-comment">// Array of subdocuments</span>
  <span class="hljs-attr">specials</span>: [{
    <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">keys</span>: <span class="hljs-built_in">String</span>
  }]
  <span class="hljs-comment">// Single subdocument</span>
  <span class="hljs-attr">ultimate</span>: {
    <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">keys</span>: <span class="hljs-built_in">String</span>
  }
})
</code></pre>
<p>You can also use the childSchema syntax if you wish to. It makes the Character schema easier to understand.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> moveSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-built_in">String</span>
})

<span class="hljs-keyword">const</span> characterSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span> },
  <span class="hljs-comment">// Array of subdocuments</span>
  <span class="hljs-attr">specials</span>: [moveSchema],
  <span class="hljs-comment">// Single subdocument</span>
  <span class="hljs-attr">ultimate</span>: moveSchema
})
</code></pre>
<h3 id="heading-creating-documents-that-contain-subdocuments">Creating documents that contain subdocuments</h3>
<p>There are two ways to create documents that contain subdocuments:</p>
<ol>
<li>Pass a nested object into <code>new Model</code></li>
<li>Add properties into the created document.</li>
</ol>
<h4 id="heading-method-1-passing-the-entire-object">Method 1: Passing the entire object</h4>
<p>For this method, we construct a nested object that contains both Ryu's name and his moves.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span>,
  <span class="hljs-attr">specials</span>: [{
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Hadoken'</span>,
    <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ P'</span>
  }, {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Shoryuken'</span>,
    <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†’ â†“ â†˜ â†’ P'</span>
  }, {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Tatsumaki Senpukyaku'</span>,
    <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†™ â† K'</span>
  }],
  <span class="hljs-attr">ultimate</span>: {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Shinku Hadoken'</span>,
    <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ â†“ â†˜ â†’ P'</span>
  }
}
</code></pre>
<p>Then, we pass this object into <code>new Character</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> char = <span class="hljs-keyword">new</span> Character(ryu)
<span class="hljs-keyword">const</span> doc = <span class="hljs-keyword">await</span> char.save()
<span class="hljs-built_in">console</span>.log(doc)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-subdocuments/ryu.png" alt="Image of Ryu's document." width="600" height="400" loading="lazy"></figure>

<h4 id="heading-method-2-adding-subdocuments-later">Method 2: Adding subdocuments later</h4>
<p>For this method, we create a character with <code>new Character</code> first.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">new</span> Character({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
</code></pre>
<p>Then, we edit the character to add special moves:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">new</span> Character({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
<span class="hljs-keyword">const</span> ryu.specials = [{
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Hadoken'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ P'</span>
}, {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Shoryuken'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†’ â†“ â†˜ â†’ P'</span>
}, {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Tatsumaki Senpukyaku'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†™ â† K'</span>
}]
</code></pre>
<p>Then, we edit the character to add the ultimate move:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">new</span> Character({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })

<span class="hljs-comment">// Adds specials</span>
<span class="hljs-keyword">const</span> ryu.specials = [{
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Hadoken'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ P'</span>
}, {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Shoryuken'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†’ â†“ â†˜ â†’ P'</span>
}, {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Tatsumaki Senpukyaku'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†™ â† K'</span>
}]

<span class="hljs-comment">// Adds ultimate</span>
ryu.ultimate = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Shinku Hadoken'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ â†“ â†˜ â†’ P'</span>
}
</code></pre>
<p>Once we're satisfied with <code>ryu</code>, we run <code>save</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">new</span> Character({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })

<span class="hljs-comment">// Adds specials</span>
<span class="hljs-keyword">const</span> ryu.specials = [{
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Hadoken'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ P'</span>
}, {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Shoryuken'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†’ â†“ â†˜ â†’ P'</span>
}, {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Tatsumaki Senpukyaku'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†™ â† K'</span>
}]

<span class="hljs-comment">// Adds ultimate</span>
ryu.ultimate = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Shinku Hadoken'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ â†“ â†˜ â†’ P'</span>
}

<span class="hljs-keyword">const</span> doc = <span class="hljs-keyword">await</span> ryu.save()
<span class="hljs-built_in">console</span>.log(doc)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-subdocuments/ryu.png" alt="Image of Ryu's document." width="600" height="400" loading="lazy"></figure>

<h3 id="heading-updating-array-subdocuments">Updating array subdocuments</h3>
<p>The easiest way to update subdocuments is:</p>
<ol>
<li>Use <code>findOne</code> to find the document</li>
<li>Get the array</li>
<li>Change the array</li>
<li>Run <code>save</code></li>
</ol>
<p>For example, let's say we want to add <code>Jodan Sokutou Geri</code> to Ryu's special moves. The keys for <code>Jodan Sokutou Geri</code> are <code>â†“ â†˜ â†’ K</code>.</p>
<p>First, we find Ryu with <code>findOne</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Characters.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
</code></pre>
<p>Mongoose documents behave like regular JavaScript objects. We can get the <code>specials</code> array by writing <code>ryu.specials</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Characters.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
<span class="hljs-keyword">const</span> specials = ryu.specials
<span class="hljs-built_in">console</span>.log(specials)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-subdocuments/specials.png" alt="Log of specials." width="600" height="400" loading="lazy"></figure>

<p>This <code>specials</code> array is a normal JavaScript array.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Characters.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
<span class="hljs-keyword">const</span> specials = ryu.specials
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Array</span>.isArray(specials)) <span class="hljs-comment">// true</span>
</code></pre>
<p>We can use the <code>push</code> method to add a new item into <code>specials</code>,</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Characters.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
ryu.specials.push({
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Jodan Sokutou Geri'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ K'</span>
})
</code></pre>
<p>After updating <code>specials</code>, we run <code>save</code> to save Ryu to the database.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Characters.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
ryu.specials.push({
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Jodan Sokutou Geri'</span>,
  <span class="hljs-attr">keys</span>: <span class="hljs-string">'â†“ â†˜ â†’ K'</span>
})

<span class="hljs-keyword">const</span> updated = <span class="hljs-keyword">await</span> ryu.save()
<span class="hljs-built_in">console</span>.log(updated)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-subdocuments/ryu-updated.png" alt="Ryu updated with Jodan Sokutou Geri" width="600" height="400" loading="lazy"></figure>

<h3 id="heading-updating-a-single-subdocument">Updating a single subdocument</h3>
<p>It's even easier to update single subdocuments. You can edit the document directly like a normal object.</p>
<p>Let's say we want to change Ryu's ultimate name from Shinku Hadoken to Dejin Hadoken. What we do is:</p>
<ol>
<li>Use <code>findOne</code> to get Ryu.</li>
<li>Change the <code>name</code> in <code>ultimate</code></li>
<li>Run <code>save</code></li>
</ol>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ryu = <span class="hljs-keyword">await</span> Characters.findOne({ <span class="hljs-attr">name</span>: <span class="hljs-string">'Ryu'</span> })
ryu.ultimate.name = <span class="hljs-string">'Dejin Hadoken'</span>

<span class="hljs-keyword">const</span> updated = <span class="hljs-keyword">await</span> ryu.save()
<span class="hljs-built_in">console</span>.log(updated)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-subdocuments/ryu-3.png" alt="Ryu document with Dejin Hadoken." width="600" height="400" loading="lazy"></figure>

<h2 id="heading-population">Population</h2>
<p>MongoDB documents have a size limit of 16MB. This means you can use subdocuments (or embedded documents) if they are small in number.</p>
<p>For example, Street Fighter characters have a limited number of moves. Ryu only has 4 special moves. In this case, it's okay to use embed moves directly into Ryu's character document.</p>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/ryu.png" alt="Ryu's document." width="600" height="400" loading="lazy"></figure>

<p>But if you have data that can contain an unlimited number of subdocuments, you need to design your database differently.</p>
<p>One way is to create two separate models and combine them with populate.</p>
<h3 id="heading-creating-the-models">Creating the models</h3>
<p>Let's say you want to create a blog. And you want to store the blog content with MongoDB. Each blog has a title, content, and comments.</p>
<p>Your first schema might look like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> blogPostSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">title</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">comments</span>: [{
    <span class="hljs-attr">comment</span>: <span class="hljs-built_in">String</span>
  }]
})

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'BlogPost'</span>, blogPostSchema)
</code></pre>
<p>There's a problem with this schema.</p>
<p>A blog post can have an unlimited number of comments. If a blog post explodes in popularity and comments swell up, the document might exceed the 16MB limit imposed by MongoDB.</p>
<p>This means we should not embed comments in blog posts. We should create a separate collection for comments.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> comments = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">comment</span>: <span class="hljs-built_in">String</span>
})

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'Comment'</span>, commentSchema)
</code></pre>
<p>In Mongoose, we can link up the two models with Population.</p>
<p>To use Population, we need to:</p>
<ol>
<li>Set <code>type</code> of a property to <code>Schema.Types.ObjectId</code></li>
<li>Set <code>ref</code> to the model we want to link too.</li>
</ol>
<p>Here, we want <code>comments</code> in <code>blogPostSchema</code> to link to the Comment collection. This is the schema we'll use:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> blogPostSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">title</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">comments</span>: [{ <span class="hljs-attr">type</span>: Schema.Types.ObjectId, <span class="hljs-attr">ref</span>: <span class="hljs-string">'Comment'</span> }]
})

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'BlogPost'</span>, blogPostSchema)
</code></pre>
<h3 id="heading-creating-a-blog-post">Creating a blog post</h3>
<p>Let's say you want to create a blog post. To create the blog post, you use <code>new BlogPost</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> blogPost = <span class="hljs-keyword">new</span> BlogPost({
  <span class="hljs-attr">title</span>: <span class="hljs-string">'Weather'</span>,
  <span class="hljs-attr">content</span>: <span class="hljs-string">`How's the weather today?`</span>
})
</code></pre>
<p>A blog post can have zero comments. We can save this blog post with <code>save</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> doc = <span class="hljs-keyword">await</span> blogPost.save()
<span class="hljs-built_in">console</span>.log(doc)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/blog-post-no-comments.png" alt="Created a blog post document without comments." width="600" height="400" loading="lazy"></figure>

<h3 id="heading-creating-comments">Creating comments</h3>
<p>Now let's say we want to create a comment for the blog post. To do this, we create and save the comment.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> comment = <span class="hljs-keyword">new</span> Comment({
  <span class="hljs-attr">comment</span>: <span class="hljs-string">`It's damn hot today`</span>
})

<span class="hljs-keyword">const</span> savedComment = <span class="hljs-keyword">await</span> comment.save()
<span class="hljs-built_in">console</span>.log(savedComment)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/comment.png" alt="Created and saved a comment." width="600" height="400" loading="lazy"></figure>

<p>Notice the saved comment has an <code>_id</code> attribute. We need to add this <code>_id</code> attribute into the blog post's <code>comments</code> array. This creates the link.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Saves comment to Database</span>
<span class="hljs-keyword">const</span> savedComment = <span class="hljs-keyword">await</span> comment.save()

<span class="hljs-comment">// Adds comment to blog post</span>
<span class="hljs-comment">// Then saves blog post to database</span>
<span class="hljs-keyword">const</span> blogPost = <span class="hljs-keyword">await</span> BlogPost.findOne({ <span class="hljs-attr">title</span>: <span class="hljs-string">'Weather'</span> })
blogPost.comments.push(savedComment._id)
<span class="hljs-keyword">const</span> savedPost = <span class="hljs-keyword">await</span> blogPost.save()
<span class="hljs-built_in">console</span>.log(savedPost)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/blog-post-with-comments.png" alt="blog-post-with-comments" width="600" height="400" loading="lazy"><figcaption>Blog post with comments.</figcaption></figure>

<h3 id="heading-searching-blog-posts-and-their-comments">Searching blog posts and their comments</h3>
<p>If you tried to search for the blog post, you'll see the blog post has an array of comment IDs.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> blogPost = <span class="hljs-keyword">await</span> BlogPost.findOne({ <span class="hljs-attr">title</span>: <span class="hljs-string">'Weather'</span> })
<span class="hljs-built_in">console</span>.log(blogPost)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/blog-post-with-comments.png" alt="Found blog post contains comment ids." width="600" height="400" loading="lazy"></figure>

<p>There are four ways to get comments.</p>
<ol>
<li>Mongoose population</li>
<li>Manual way #1</li>
<li>Manual way #2</li>
<li>Manual way #3</li>
</ol>
<h4 id="heading-mongoose-population">Mongoose Population</h4>
<p>Mongoose allows you to fetch linked documents with the <code>populate</code> method. What you need to do is call <code>.populate</code> when you execute with <code>findOne</code>.</p>
<p>When you call populate, you need to pass in the <code>key</code> of the property you want to populate. In this case, the <code>key</code> is <code>comments</code>. (Note: Mongoose calls this <code>key</code> a "path").</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> blogPost = <span class="hljs-keyword">await</span> BlogPost.findOne({ <span class="hljs-attr">title</span>: <span class="hljs-string">'Weather'</span> })
  .populate(<span class="hljs-string">'comments'</span>)
<span class="hljs-built_in">console</span>.log(blogPost)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/populated.png" alt="Comments populated by Mongoose." width="600" height="400" loading="lazy"></figure>

<h4 id="heading-manual-way-method-1">Manual way (method 1)</h4>
<p>Without Mongoose Populate, you need to find the comments manually. First, you need to get the array of comments.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> blogPost = <span class="hljs-keyword">await</span> BlogPost.findOne({ <span class="hljs-attr">title</span>: <span class="hljs-string">'Weather'</span> })
  .populate(<span class="hljs-string">'comments'</span>)
<span class="hljs-keyword">const</span> commentIDs = blogPost.comments
</code></pre>
<p>Then, you loop through <code>commentIDs</code> to find each comment. If you go with this method, it's slightly faster to use <code>Promise.all</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> commentPromises = commentIDs.map(<span class="hljs-function"><span class="hljs-params">_id</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> Comment.findOne({ _id })
})
<span class="hljs-keyword">const</span> comments = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(commentPromises)
<span class="hljs-built_in">console</span>.log(comments)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/found-comments.png" alt="Comments found." width="600" height="400" loading="lazy"></figure>


<h4 id="heading-manual-way-method-2">Manual way (method 2)</h4>
<p>Mongoose gives you an <code>$in</code> operator. You can use this <code>$in</code> operator to find all comments within an array. This syntax takes a little effort to get used to.</p>
<p>If I had to do the manual way, I'd prefer Manual #1 over this.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> commentIDs = blogPost.comments
<span class="hljs-keyword">const</span> comments = <span class="hljs-keyword">await</span> Comment.find({
    <span class="hljs-string">'_id'</span>: { <span class="hljs-attr">$in</span>: commentIDs }
})

<span class="hljs-built_in">console</span>.log(comments)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/found-comments.png" alt="Comments found." width="600" height="400" loading="lazy"></figure>

<h4 id="heading-manual-way-method-3">Manual way (method 3)</h4>
<p>For the third method, we need to change the schema. When we save a comment, we link the comment to the blog post.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Linking comments to blog post</span>
<span class="hljs-keyword">const</span> commentSchema = <span class="hljs-keyword">new</span> Schema({
  <span class="hljs-attr">comment</span>: <span class="hljs-built_in">String</span>
  <span class="hljs-attr">blogPost</span>: [{ <span class="hljs-attr">type</span>: Schema.Types.ObjectId, <span class="hljs-attr">ref</span>: <span class="hljs-string">'BlogPost'</span> }]
})

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'Comment'</span>, commentSchema)
</code></pre>
<p>You need to save the comment into the blog post, and the blog post id into the comment.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> blogPost = <span class="hljs-keyword">await</span> BlogPost.findOne({ <span class="hljs-attr">title</span>: <span class="hljs-string">'Weather'</span> })

<span class="hljs-comment">// Saves comment</span>
<span class="hljs-keyword">const</span> comment = <span class="hljs-keyword">new</span> Comment({
  <span class="hljs-attr">comment</span>: <span class="hljs-string">`It's damn hot today`</span>,
  <span class="hljs-attr">blogPost</span>: blogPost._id
})
<span class="hljs-keyword">const</span> savedComment = comment.save()

<span class="hljs-comment">// Links blog post to comment</span>
blogPost.comments.push(savedComment._id)
<span class="hljs-keyword">await</span> blogPost.save()
</code></pre>
<p>Once you do this, you can search the Comments collection for comments that match your blog post's id.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Searches for comments</span>
<span class="hljs-keyword">const</span> blogPost = <span class="hljs-keyword">await</span> BlogPost.findOne({ <span class="hljs-attr">title</span>: <span class="hljs-string">'Weather'</span> })
<span class="hljs-keyword">const</span> comments = <span class="hljs-keyword">await</span> Comment.find({ <span class="hljs-attr">_id</span>: blogPost._id })
<span class="hljs-built_in">console</span>.log(comments)
</code></pre>
<figure><img src="https://zellwk.com/images/2019/mongoose-population/found-comments.png" alt="Comments found." width="600" height="400" loading="lazy"></figure>

<p>I'd prefer Manual #3 over Manual #1 and Manual #2.</p>
<p>And Population beats all three manual methods.</p>
<h2 id="heading-quick-summary">Quick Summary</h2>
<p>You learned to use Mongoose on three different levels in this article: </p>
<ol>
<li>Basic Mongoose </li>
<li>Mongoose subdocuments</li>
<li>Mongoose population </li>
</ol>
<p>That's it!</p>
<hr>

<p>Thanks for reading. This article was originally posted on <a target="_blank" href="https://zellwk.com/blog/mongoose">my blog</a>.  Sign up for my newsletter if you want more articles to help you become a better frontend developer. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to allow users to upload images with Node/Express, Mongoose, and Cloudinary ]]>
                </title>
                <description>
                    <![CDATA[ By Glyn Lewington Are you building a full-stack app and want to let users upload an image but you’re not sure how? In my experience, this is always achieved by having users input a link and saving this string to your database. This works great and is... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-allow-users-to-upload-images-with-node-express-mongoose-and-cloudinary-84cefbdff1d9/</link>
                <guid isPermaLink="false">66d45edb052ad259f07e4ad0</guid>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 23 Aug 2018 14:36:36 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*ETsmhAGOpiWfK06i" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Glyn Lewington</p>
<p>Are you building a full-stack app and want to let users upload an image but you’re not sure how? In my experience, this is always achieved by having users input a link and saving this string to your database. This works great and is quick and easy, but it’s also kind of cheating. What kind of app makes you first go to another site and upload your image, and then come back and link to it?</p>
<p>So, what’s the solution?</p>
<p>Allow the user to input a file, then on your server, upload this file to a cloud service and save this in your database. Cloudinary is great for this. It’s dedicated to media uploads. It has great documentation. It allows for transformations. <strong>And</strong> has a huge free plan (10 GB storage). You can sign up for <a target="_blank" href="https://cloudinary.com/invites/lpov9zyyucivvxsnalc5/yytj9stwvdsschwyccf8">Cloudinary here</a> (I get nothing for this).</p>
<h3 id="heading-lets-get-started-on-the-front-end">Let’s get started on the front-end</h3>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">'/api/images'</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">enctype</span>=<span class="hljs-string">"multipart/form-data"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'file'</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'image'</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>This should look familiar. All you need is a form which will submit the information to the server. Enctype is required for submitting files to the server.</p>
<p>That’s the front-end solved.</p>
<h3 id="heading-the-back-end">The back-end</h3>
<p>Now, the back-end is where all the magic happens. You will need all the usual dependencies for working with <strong>Express</strong> and <strong>Mongoose</strong>. In addition, we will utilise <strong>Multer</strong>, <strong>Cloudinary</strong>, and <strong>multer-storage-cloudinary</strong>. Multer will allow access to files submitted through the form. Cloudinary is used for configuration and uploading. multer-storage-cloudinary will make the process of combining these easy.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> multer = <span class="hljs-built_in">require</span>(<span class="hljs-string">"multer"</span>);
<span class="hljs-keyword">const</span> cloudinary = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cloudinary"</span>);
<span class="hljs-keyword">const</span> cloudinaryStorage = <span class="hljs-built_in">require</span>(<span class="hljs-string">"multer-storage-cloudinary"</span>);
</code></pre>
<p>Once the dependencies are required you need to configure them. When you sign up to Cloudinary, you will be provided your API credentials. I recommend storing these in a “.env” file to keep them secure.</p>
<p>Below we are also:</p>
<ul>
<li>setting a folder to keep all the images organised on Cloudinary for this project</li>
<li>ensuring only “.jpg” and “.png” files are uploaded</li>
<li>adding a transformation to keep the height and width consistent and to manage file size.</li>
</ul>
<p>There’s a lot more you can do in regards to transformations — you can take a look <a target="_blank" href="https://cloudinary.com/documentation/image_transformations">here</a> if you are interested.</p>
<pre><code class="lang-js">cloudinary.config({
<span class="hljs-attr">cloud_name</span>: process.env.CLOUD_NAME,
<span class="hljs-attr">api_key</span>: process.env.API_KEY,
<span class="hljs-attr">api_secret</span>: process.env.API_SECRET
});
<span class="hljs-keyword">const</span> storage = cloudinaryStorage({
<span class="hljs-attr">cloudinary</span>: cloudinary,
<span class="hljs-attr">folder</span>: <span class="hljs-string">"demo"</span>,
<span class="hljs-attr">allowedFormats</span>: [<span class="hljs-string">"jpg"</span>, <span class="hljs-string">"png"</span>],
<span class="hljs-attr">transformation</span>: [{ <span class="hljs-attr">width</span>: <span class="hljs-number">500</span>, <span class="hljs-attr">height</span>: <span class="hljs-number">500</span>, <span class="hljs-attr">crop</span>: <span class="hljs-string">"limit"</span> }]
});
<span class="hljs-keyword">const</span> parser = multer({ <span class="hljs-attr">storage</span>: storage });
</code></pre>
<p>Now that your server is all set up to receive and process these images, we can move onto setting up the route.</p>
<p>In your post route, you simply add the parser we set up before as a middleware. This will take in the file, upload it to Cloudinary, and return an object with the file information. You can access this information in the request object.</p>
<p>I like to extract just the information I want from this, to keep my database organised. At the least, you will want:</p>
<ul>
<li>the URL which can be used to display the image on the front-end</li>
<li>the public_id which will allow you to access and delete the image from Cloudinary.</li>
</ul>
<pre><code class="lang-js">app.post(<span class="hljs-string">'/api/images'</span>, parser.single(<span class="hljs-string">"image"</span>), <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(req.file) <span class="hljs-comment">// to see what is returned to you</span>
  <span class="hljs-keyword">const</span> image = {};
  image.url = req.file.url;
  image.id = req.file.public_id;
  Image.create(image) <span class="hljs-comment">// save image information in database</span>
    .then(<span class="hljs-function"><span class="hljs-params">newImage</span> =&gt;</span> res.json(newImage))
    .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
});
</code></pre>
<p>Your image will probably be part of a larger object in your database. The image URL and id can be saved as strings as a part of this.</p>
<p><em>*Image is an example placeholder for your database collection. Substitute it for your own.</em></p>
<h3 id="heading-displaying-the-image">Displaying the image</h3>
<p>When you want to display the image on the front-end, perform a database query, and then use the URL inside your image tags <code>&lt;img src=imageURL</code> /&gt;.</p>
<p>I hope this will help you in adding that little extra to your websites. It’s not that difficult once you break down each step in the process. It will give your website the professional touch and will make it stand out.</p>
<p>If you have any questions, please ask in the comments.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to write powerful schemas in JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ By Diego Haz Introducing schm, a functional and highly composable library for creating schemas in JavaScript and Node.js _Background photo by [Willi Heidelbach](https://www.flickr.com/photos/wilhei/" rel="noopener" target="blank" title="Vá para a ga... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-powerful-schemas-in-javascript-490da6233d37/</link>
                <guid isPermaLink="false">66c3564e39357f9446976593</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 21 Mar 2018 04:53:38 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*u_gVBtCyIcrWbOBv3xDCWg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Diego Haz</p>
<h4 id="heading-introducing-schmhttpsgithubcomdiegohazschm-a-functional-and-highly-composable-library-for-creating-schemas-in-javascript-and-nodejs">Introducing <a target="_blank" href="https://github.com/diegohaz/schm">schm</a>, a functional and highly composable library for creating schemas in JavaScript and Node.js</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*u_gVBtCyIcrWbOBv3xDCWg.png" alt="Image" width="800" height="448" loading="lazy">
_Background photo by [Willi Heidelbach](https://www.flickr.com/photos/wilhei/" rel="noopener" target="<em>blank" title="Vá para a galeria de Willi Heidelbach)</em></p>
<p>I’ve been working with HTML, CSS, and JavaScript since 2002. The first time I needed some sort of schema in JavaScript was just a few years ago.</p>
<p>After using many different libraries and even authoring <a target="_blank" href="https://github.com/diegohaz/querymen">one</a> and <a target="_blank" href="https://github.com/diegohaz/bodymen">another</a>, I decided to create <a target="_blank" href="https://github.com/diegohaz/schm">schm</a>. That’s the result of all my experience with schemas in JavaScript.</p>
<h3 id="heading-what-is-schmhttpsgithubcomdiegohazschm">What is <a target="_blank" href="https://github.com/diegohaz/schm">schm</a>?</h3>
<p><code>schm</code> is a group of npm packages to help developers deal with schemas in JavaScript and Node.js.</p>
<p>It’s highly inspired by <a target="_blank" href="http://mongoosejs.com/docs/guide.html">Mongoose Schemas</a>. Actually, they’re so similar that you can use <code>schm</code> parameters within Mongoose Schemas and vice-versa. It's not MongoDB specific, though. You can use it for everything in JavaScript.</p>
<h3 id="heading-what-kind-of-problems-does-schmhttpsgithubcomdiegohazschm-solve">What kind of problems does <a target="_blank" href="https://github.com/diegohaz/schm">schm</a> solve?</h3>
<h4 id="heading-parsing-and-validation-of-form-values">? Parsing and validation of form values</h4>
<p>On the client, you can use schemas to define models for HTML forms. It makes it easier to transform and validate values. Also, if you’re using Node.js on the server, you can use the same schema. The result is a consistent behavior between client and server validations.</p>
<h4 id="heading-parsing-and-validation-of-query-string">? Parsing and validation of query string</h4>
<p>Consider the following query string: <code>/?term=John&amp;page=2&amp;limit=10</code> . By combining packages such as <a target="_blank" href="https://github.com/diegohaz/schm/tree/master/packages/schm-koa">schm-koa</a>, <a target="_blank" href="https://github.com/diegohaz/schm/tree/master/packages/schm-express">schm-express</a> and/or <a target="_blank" href="https://github.com/diegohaz/schm/tree/master/packages/schm-mongo">schm-mongo</a>, you will be able to parse and validate query strings with search terms and pagination with ease.</p>
<h4 id="heading-communication-between-client-and-server">☊ Communication between client and server</h4>
<p>If you have an app that consumes resources from a REST API, for example, you can use schemas to define, on the client, the object structure your client expects to receive from the server. If something changes on the server (properties have been renamed, for example), you can just update your schema so your entire application will continue to work.</p>
<h3 id="heading-creating-a-schema">Creating a schema</h3>
<p>A simple schema is just a map of keys and types:</p>
<p>That’s the same as using a <code>type</code> property:</p>
<p>A schema can also be a map between keys and default values. Types will be automatically inferred:</p>
<p>That’s equivalent to doing the following:</p>
<p>To learn more about how to write schemas, take a look at <a target="_blank" href="http://mongoosejs.com/docs/guide.html">Mongoose Schemas</a>.</p>
<h3 id="heading-parsing-values">Parsing values</h3>
<p>After defining the schema, you can use it to parse values. This process will convert values to the proper types, as well as applying other parsers defined in the schema. These are the available parsers: <code>type</code>, <code>default</code> , <code>set</code> , <code>get</code> , <code>trim</code>, <code>uppercase</code> , <code>lowercase</code> .</p>
<p>The output will be something like this:</p>
<pre><code>{  <span class="hljs-attr">name</span>: <span class="hljs-string">"HAZ"</span>,  <span class="hljs-attr">birthdate</span>: Tue Apr <span class="hljs-number">10</span> <span class="hljs-number">1990</span> <span class="hljs-number">00</span>:<span class="hljs-number">00</span>:<span class="hljs-number">00</span> GMT,}
</code></pre><h3 id="heading-validating-values">Validating values</h3>
<p>Just like in <a target="_blank" href="http://mongoosejs.com/docs/guide.html">Mongoose Schemas</a>, you can define validation rules within your schemas. These are the available validators: <code>validate</code> , <code>required</code> , <code>match</code> , <code>enum</code> , <code>max</code> , <code>min</code> , <code>maxlength</code> , <code>minlength</code> .</p>
<p>You can also create custom parsers and validators by extending the schema. We’ll talk about it later in this article.</p>
<p>The validation error will be, by default, an array of objects describing the errors.</p>
<pre><code>[  {    <span class="hljs-attr">message</span>: <span class="hljs-string">"age must be greater than or equal 18"</span>,    <span class="hljs-attr">min</span>: <span class="hljs-number">18</span>,    <span class="hljs-attr">param</span>: <span class="hljs-string">"age"</span>,    <span class="hljs-attr">validator</span>: <span class="hljs-string">"min"</span>,    <span class="hljs-attr">value</span>: <span class="hljs-number">17</span>,  }]
</code></pre><p>If the validation passes, it will return the parsed values, just like <code>parse()</code>.</p>
<h3 id="heading-composing-multiple-schemas">Composing multiple schemas</h3>
<p>Say you have separate schemas describing a <code>body</code>, <code>identity</code> and other things, and want to compose them to build a <code>human</code> schema. That's as easy as it sounds:</p>
<p>Another way to compose schemas is through nesting. A schema can be used as a <code>type</code> within another schema:</p>
<h3 id="heading-extending-schemas">Extending schemas</h3>
<p>This is the part where <code>schm</code> really shines. You can add custom parsers and validators or even replace the default behavior of <code>parse</code> and <code>validate</code> methods by creating schema groups.</p>
<p>A <strong>schema group</strong> is a function that receives the previous schema as the only argument. Besides previous <code>params</code> , <code>parsers</code> and <code>validators</code> , the schema object has a <code>merge</code> method, which is useful for schema group functions to merge new functionality into the previous schemas.</p>
<p>The output of the above snippet will be something like this:</p>
<pre><code>{  <span class="hljs-attr">name</span>: <span class="hljs-string">"Haz!!!"</span>,  <span class="hljs-attr">age</span>: <span class="hljs-number">27</span>,}
</code></pre><p>If you want to go further and learn more about how to create custom parsers, take a look at how parsers are written inside the core library <a target="_blank" href="https://github.com/diegohaz/schm/blob/master/packages/schm/src/parsers.js">here</a>.</p>
<p>By extending schemas, we can create many kinds of things. That’s how most of the <code>schm</code> satellite libraries, such as <a target="_blank" href="https://github.com/diegohaz/schm/tree/master/packages/schm-translate">schm-translate</a>, <a target="_blank" href="https://github.com/diegohaz/schm/tree/master/packages/schm-computed">schm-computed</a> and <a target="_blank" href="https://github.com/diegohaz/schm/tree/master/packages/schm-mongo">schm-mongo</a>, are written.</p>
<p>We’re going to talk about one of them now.</p>
<h3 id="heading-renaming-values-keys">Renaming values keys</h3>
<p><a target="_blank" href="https://github.com/diegohaz/schm/tree/master/packages/schm-translate">schm-translate</a> is one of the simplest, yet powerful, satellite libraries of <code>schm</code> . It's a few more than <a target="_blank" href="https://github.com/diegohaz/schm/blob/master/packages/schm-translate/src/index.js">10 lines of code</a> compressed into one function which lets you translate values keys to your schema keys.</p>
<p>Say you’re working on a webapp that consumes resources from a REST API. Suddenly, developers change things on the API, which makes the response body return a slightly different model than the one the client expected. Instead of an <code>email</code> property, it returns now an array of <code>emails</code> .</p>
<p>This will probably make your app to break. If you don’t have a schema or any other centralized way to handle that object, you will need to update every part of the application to conform to the server changes.</p>
<p>With <code>schm</code> and <code>schm-translate</code> , it can be solved by changing a few lines of code in just one place:</p>
<p>The output will be exactly the one your app expected before the change:</p>
<pre><code>{  <span class="hljs-attr">name</span>: <span class="hljs-string">"Haz"</span>,  <span class="hljs-attr">email</span>: <span class="hljs-string">"hazdiego@gmail.com"</span>,}
</code></pre><p><a target="_blank" href="https://github.com/diegohaz/schm#packages">Click here to see the list of all packages</a></p>
<h3 id="heading-how-is-this-different-from-other-schema-libraries">How is this different from other schema libraries?</h3>
<p>A common question is the difference between <code>schm</code> and other libraries, such as <a target="_blank" href="https://github.com/hapijs/joi">Joi</a> and <a target="_blank" href="https://github.com/epoberezkin/ajv">ajv</a> (which follows <a target="_blank" href="http://json-schema.org/">JSON Schema</a> spec).</p>
<p>Comparing to <code>ajv</code>, <code>schm</code> doesn't follow any particular spec. Instead, it tries to mimic the Mongoose Schema API. Also, even though <code>ajv</code> has some parsing features, they're limited to <a target="_blank" href="https://github.com/epoberezkin/ajv#assigning-defaults">default values</a> and <a target="_blank" href="https://github.com/epoberezkin/ajv#coercing-data-types">type coercion</a>.</p>
<p>In <code>schm</code>, the ability to parse values based on the schema is what makes it possible to transform a query string into a MongoDB query, for example.</p>
<p>That said, both <code>Joi</code> and <code>ajv</code> can be combined with <code>schm</code> . You can easily extend it to use a different validation method:</p>
<h3 id="heading-thank-you-for-reading-this">Thank you for reading this!</h3>
<p>If you like it and find it useful, here are some things you can do to show your support:</p>
<ul>
<li>Hit the clap ? button on this article a few times (up to 50)</li>
<li>Give a star ⭐️ on GitHub: <a target="_blank" href="https://github.com/diegohaz/schm">https://github.com/diegohaz/schm</a></li>
<li>Follow me on GitHub: <a target="_blank" href="https://github.com/diegohaz">https://github.com/diegohaz</a></li>
<li>Follow me on Twitter: <a target="_blank" href="https://twitter.com/diegohaz">https://twitter.com/diegohaz</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Introduction to Mongoose for MongoDB ]]>
                </title>
                <description>
                    <![CDATA[ By Nick Karnik Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in M... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/introduction-to-mongoose-for-mongodb-d2a7aa593c57/</link>
                <guid isPermaLink="false">66c35863c7095d76345eaf9c</guid>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongoose ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 11 Feb 2018 20:00:49 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*uTZXsVta4TwghNobMkZeZg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nick Karnik</p>
<p>Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in MongoDB.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*b5piDNW1dqlkJWKe." alt="Image" width="800" height="390" loading="lazy">
<em>Object Mapping between Node and MongoDB managed via Mongoose</em></p>
<p>MongoDB is a schema-less NoSQL document database. It means you can store JSON documents in it, and the structure of these documents can vary as it is not enforced like SQL databases. This is one of the advantages of using NoSQL as it speeds up application development and reduces the complexity of deployments.</p>
<p>Below is an example of how data is stored in Mongo vs. SQL Database:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*rcotALFe2LeebN_y." alt="Image" width="594" height="956" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*QOKLctlRwxs5uKVo." alt="Image" width="682" height="931" loading="lazy">
<em>NoSQL Documents vs. Relational Tables in SQL</em></p>
<h3 id="heading-terminologies">Terminologies</h3>
<h4 id="heading-collections">Collections</h4>
<p><a target="_blank" href="https://mongoosejs.com/docs/guide.html#collection"><em>Collections</em></a> in Mongo are equivalent to tables in relational databases. They can hold multiple JSON documents.</p>
<h4 id="heading-documents">Documents</h4>
<p><a target="_blank" href="https://mongoosejs.com/docs/documents.html"><em>Documents</em></a> are equivalent to records or rows of data in SQL. While a SQL row can reference data in other tables, Mongo documents usually combine that in a document.</p>
<h4 id="heading-fields">Fields</h4>
<p><em>Fields</em>, also known as properties or attributes, are similar to columns in a SQL table. In the image above, <code>FirstName</code>, <code>LastName</code>, <code>Email</code>, and <code>Phone</code> are all fields.</p>
<h4 id="heading-schema">Schema</h4>
<p>While Mongo is schema-less, SQL defines a schema via the table definition. A Mongoose <a target="_blank" href="https://mongoosejs.com/docs/guide.html#schemas"><em>schema</em></a> is a document data structure (or shape of the document) that is enforced via the application layer.</p>
<h4 id="heading-schematypes">SchemaTypes</h4>
<p>While Mongoose schemas define the overall structure or shape of a document, <em><a target="_blank" href="https://mongoosejs.com/docs/schematypes.html">SchemaTypes</a></em> define the expected data type for individual fields (<code>String</code>, <code>Number</code>, <code>Boolean</code>, and so on).</p>
<p>You can also pass in useful options like <code>required</code> to make a field non-optional, <code>default</code> to set a default value for the field, and many more.</p>
<h4 id="heading-models">Models</h4>
<p><a target="_blank" href="https://mongoosejs.com/docs/models.html"><em>Models</em></a> are higher-order constructors that take a schema and create an instance of a document equivalent to records in a relational database.</p>
<h4 id="heading-example">Example</h4>
<p>Here's a small code snippet to illustrate some of the terminology above:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> puppySchema = <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">age</span>: <span class="hljs-built_in">Number</span>
});

<span class="hljs-keyword">const</span> Puppy = mongoose.model(<span class="hljs-string">'Puppy'</span>, puppySchema);
</code></pre>
<p>In the code above, <code>puppySchema</code> defines the shape of the document which has two fields, <code>name</code>, and <code>age</code>.</p>
<p>The <code>SchemaType</code> for <code>name</code> is <code>String</code> and for <code>age</code> is <code>Number</code>. Note that you can define the <code>SchemaType</code> for a field by using an object with a <code>type</code> property like with <code>name</code>. Or you can apply a <code>SchemaType</code> directly to the field like with <code>age</code>.</p>
<p>Also, notice that the <code>SchemaType</code> for <code>name</code> has the option <code>required</code> set to <code>true</code>. To use options like <code>required</code> and <code>lowercase</code> for a field, you need to use an object to set the <code>SchemaType</code>.</p>
<p>At the bottom of the snippet, <code>puppySchema</code> is compiled into a model named <code>Puppy</code>, which can then be used to construct documents in an application.</p>
<h3 id="heading-getting-started">Getting Started</h3>
<h4 id="heading-mongo-installation">Mongo Installation</h4>
<p>Before we get started, let’s setup Mongo. You can choose from <strong>one of the following options</strong> (we are using option #1 for this article):</p>
<ol>
<li>Download the appropriate MongoDB version for your Operating System from the <a target="_blank" href="https://www.mongodb.com/download-center#community">MongoDB Website</a> and follow their installation instructions</li>
<li><a target="_blank" href="http://docs.mlab.com/">Create a free sandbox database</a> subscription on mLab</li>
<li><a target="_blank" href="https://docs.docker.com/samples/library/mongo/">Install Mongo using Docker</a> if you prefer to use Docker</li>
</ol>
<p>Let’s navigate through some of the basics of Mongoose by implementing a model that represents data for a simplified address book.</p>
<p>I am using Visual Studio Code, Node 8.9, and NPM 5.6. Fire up your favorite IDE, create a blank project, and let’s get started! We will be using the limited ES6 syntax in Node, so we won’t be configuring Babel.</p>
<h4 id="heading-npm-install">NPM Install</h4>
<p>Let’s go to the project folder and initialize our project</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>Let’s install Mongoose and a validation library with the following command:</p>
<pre><code class="lang-bash">npm install mongoose validator
</code></pre>
<p>The above install command will install the latest version of the libraries. The Mongoose syntax in this article is specific to Mongoose v5 and beyond.</p>
<h4 id="heading-database-connection">Database Connection</h4>
<p>Create a file <code>./src/database.js</code> under the project root.</p>
<p>Next, we will add a simple class with a method that connects to the database.</p>
<p>Your connection string will vary based on your installation.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">const</span> server = <span class="hljs-string">'127.0.0.1:27017'</span>; <span class="hljs-comment">// REPLACE WITH YOUR DB SERVER</span>
<span class="hljs-keyword">const</span> database = <span class="hljs-string">'fcc-Mail'</span>; <span class="hljs-comment">// REPLACE WITH YOUR DB NAME</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Database</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">this</span>._connect();
  }

  _connect() {
    mongoose
      .connect(<span class="hljs-string">`mongodb://<span class="hljs-subst">${server}</span>/<span class="hljs-subst">${database}</span>`</span>)
      .then(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Database connection successful'</span>);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Database connection error'</span>);
      });
  }
}

<span class="hljs-built_in">module</span>.exports = <span class="hljs-keyword">new</span> Database();
</code></pre>
<p>The <code>require(‘mongoose’)</code> call above returns a Singleton object. It means that the first time you call <code>require(‘mongoose’)</code>, it is creating an instance of the Mongoose class and returning it. On subsequent calls, it will return the same instance that was created and returned to you the first time because of how module import/export works in ES6.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*RvVsD_byUakUzuCj." alt="Image" width="800" height="339" loading="lazy">
<em>Module import/require work-flow</em></p>
<p>Similarly, we have turned our <code>Database</code> class into a singleton by returning an instance of the class in the <code>module.exports</code> statement because we only need a single connection to the database.</p>
<p>ES6 makes it very easy for us to create a singleton (single instance) pattern because of how the module loader works by caching the response of a previously imported file.</p>
<h3 id="heading-mongoose-schema-vs-model">Mongoose Schema vs. Model</h3>
<p>A Mongoose model is a wrapper on the Mongoose schema. A Mongoose schema defines the structure of the document, default values, validators, etc., whereas a Mongoose model provides an interface to the database for creating, querying, updating, deleting records, etc.</p>
<p>Creating a Mongoose model comprises primarily of three parts:</p>
<h4 id="heading-1-referencing-mongoose"><strong>1. Referencing Mongoose</strong></h4>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
</code></pre>
<p>This reference will be the same as the one that was returned when we connected to the database, which means the schema and model definitions will not need to explicitly connect to the database.</p>
<h4 id="heading-2-defining-the-schema">2. Defining the Schema</h4>
<p>A schema defines document properties through an object where the key name corresponds to the property name in the collection.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> emailSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">email</span>: <span class="hljs-built_in">String</span>
});
</code></pre>
<p>Here we define a property called <code>email</code> with a schema type <code>String</code> which maps to an internal validator that will be triggered when the model is saved to the database. It will fail if the data type of the value is not a string type.</p>
<p>The following Schema Types are permitted:</p>
<ul>
<li>Array</li>
<li>Boolean</li>
<li>Buffer</li>
<li>Date</li>
<li>Mixed (A generic / flexible data type)</li>
<li>Number</li>
<li>ObjectId</li>
<li>String</li>
</ul>
<p>Mixed and ObjectId are defined under <code>require(‘mongoose’).Schema.Types</code>.</p>
<h4 id="heading-3-exporting-a-model"><strong>3. Exporting a Model</strong></h4>
<p>We need to call the model constructor on the Mongoose instance and pass it the name of the collection and a reference to the schema definition.</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'Email'</span>, emailSchema);
</code></pre>
<p>Let’s combine the above code into <code>./src/models/email.js</code> to define the contents of a basic email model:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">let</span> emailSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">email</span>: <span class="hljs-built_in">String</span>
});

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'Email'</span>, emailSchema);
</code></pre>
<p>A schema definition should be simple, but its complexity is usually based on application requirements. Schemas can be reused and they can contain several child-schemas too. In the example above, the value of the email property is a simple value type. However, it can also be an object type with additional properties on it.</p>
<p>We can create an instance of the model we defined above and populate it using the following syntax:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> EmailModel = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./email'</span>);

<span class="hljs-keyword">let</span> msg = <span class="hljs-keyword">new</span> EmailModel({
  <span class="hljs-attr">email</span>: <span class="hljs-string">'ada.lovelace@gmail.com'</span>
});
</code></pre>
<p>Let’s enhance the <code>Email</code> schema to make the email property a unique, required field and convert the value to lowercase before saving it. We can also add a validation function that will ensure that the value is a valid email address. We will reference and use the validator library installed earlier.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
<span class="hljs-keyword">let</span> validator = <span class="hljs-built_in">require</span>(<span class="hljs-string">'validator'</span>);

<span class="hljs-keyword">let</span> emailSchema = <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">required</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">lowercase</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">validate</span>: <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> validator.isEmail(value);
    }
  }
});

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'Email'</span>, emailSchema);
</code></pre>
<h3 id="heading-basic-operations">Basic Operations</h3>
<p>Mongoose has a flexible API and provides many ways to accomplish a task. We will not focus on the variations because that is out of scope for this article, but remember that most of the operations can be done in more than one way either syntactically or via the application architecture.</p>
<h4 id="heading-create-record">Create Record</h4>
<p>Let’s create an instance of the email model and save it to the database:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> EmailModel = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./email'</span>);

<span class="hljs-keyword">let</span> msg = <span class="hljs-keyword">new</span> EmailModel({
  <span class="hljs-attr">email</span>: <span class="hljs-string">'ADA.LOVELACE@GMAIL.COM'</span>
});

msg
  .save()
  .then(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(doc);
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(err);
  });
</code></pre>
<p>The result is a document that is returned upon a successful save:</p>
<pre><code class="lang-json">{ 
  _id: <span class="hljs-number">5</span>a78fe3e2f44ba8f85a2409a,
  email: 'ada.lovelace@gmail.com',
  __v: <span class="hljs-number">0</span> 
}
</code></pre>
<p>The following fields are returned (internal fields are prefixed with an underscore):</p>
<ol>
<li>The <code>_id</code> field is auto-generated by Mongo and is a primary key of the collection. Its value is a unique identifier for the document.</li>
<li>The value of the <code>email</code> field is returned. Notice that it is lower-cased because we specified the <code>lowercase: true</code> attribute in the schema.</li>
<li><code>__v</code> is the versionKey property set on each document when first created by Mongoose. Its value contains the internal revision of the document.</li>
</ol>
<p>If you try to repeat the save operation above, you will get an error because we have specified that the email field should be unique.</p>
<h4 id="heading-fetch-record">Fetch Record</h4>
<p>Let’s try to retrieve the record we saved to the database earlier. The model class exposes several static and instance methods to perform operations on the database. We will now try to find the record that we created previously using the find method and pass the email as the search term.</p>
<pre><code>EmailModel.find({
  <span class="hljs-attr">email</span>: <span class="hljs-string">'ada.lovelace@gmail.com'</span> <span class="hljs-comment">// search query</span>
})
  .then(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(doc);
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(err);
  });
</code></pre><p>The document returned will be similar to what was displayed when we created the record:</p>
<pre><code class="lang-json">{ 
  _id: <span class="hljs-number">5</span>a78fe3e2f44ba8f85a2409a,
  email: 'ada.lovelace@gmail.com',
  __v: <span class="hljs-number">0</span> 
}
</code></pre>
<h4 id="heading-update-record">Update Record</h4>
<p>Let’s modify the record above by changing the email address and adding another field to it, all in a single operation. For performance reasons, Mongoose won’t return the updated document so we need to pass an additional parameter to ask for it:</p>
<pre><code class="lang-js">EmailModel.findOneAndUpdate(
  {
    <span class="hljs-attr">email</span>: <span class="hljs-string">'ada.lovelace@gmail.com'</span> <span class="hljs-comment">// search query</span>
  },
  {
    <span class="hljs-attr">email</span>: <span class="hljs-string">'theoutlander@live.com'</span> <span class="hljs-comment">// field:values to update</span>
  },
  {
    <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// return updated doc</span>
    <span class="hljs-attr">runValidators</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">// validate before update</span>
  }
)
  .then(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(doc);
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(err);
  });
</code></pre>
<p>The document returned will contain the updated email:</p>
<pre><code class="lang-json">{ 
  _id: <span class="hljs-number">5</span>a78fe3e2f44ba8f85a2409a,
  email: 'theoutlander@live.com',
  __v: <span class="hljs-number">0</span> 
}
</code></pre>
<h4 id="heading-delete-record">Delete Record</h4>
<p>We will use the <code>findOneAndRemove</code> call to delete a record. It returns the original document that was removed:</p>
<pre><code class="lang-js">EmailModel.findOneAndRemove({
  <span class="hljs-attr">email</span>: <span class="hljs-string">'theoutlander@live.com'</span>
})
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(response);
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(err);
  });
</code></pre>
<h3 id="heading-helpers">Helpers</h3>
<p>We have looked at some of the basic functionality above known as CRUD (Create, Read, Update, Delete) operations, but Mongoose also provides the ability to configure several types of helper methods and properties. These can be used to further simplify working with data.</p>
<p>Let’s create a user schema in <code>./src/models/user.js</code> with the fields<code>firstName</code> and <code>lastName</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">let</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">firstName</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">lastName</span>: <span class="hljs-built_in">String</span>
});

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'User'</span>, userSchema);
</code></pre>
<h4 id="heading-virtual-property">Virtual Property</h4>
<p>A virtual property is not persisted to the database. We can add it to our schema as a helper to get and set values.</p>
<p>Let’s create a virtual property called <code>fullName</code> which can be used to set values on <code>firstName</code> and <code>lastName</code> and retrieve them as a combined value when read:</p>
<pre><code class="lang-js">userSchema.virtual(<span class="hljs-string">'fullName'</span>).get(<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>.firstName + <span class="hljs-string">' '</span> + <span class="hljs-built_in">this</span>.lastName;
});

userSchema.virtual(<span class="hljs-string">'fullName'</span>).set(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">name</span>) </span>{
  <span class="hljs-keyword">let</span> str = name.split(<span class="hljs-string">' '</span>);

  <span class="hljs-built_in">this</span>.firstName = str[<span class="hljs-number">0</span>];
  <span class="hljs-built_in">this</span>.lastName = str[<span class="hljs-number">1</span>];
});
</code></pre>
<p>Callbacks for get and set must use the function keyword as we need to access the model via the <code>this</code> keyword. Using fat arrow functions will change what <code>this</code> refers to.</p>
<p>Now, we can set <code>firstName</code> and <code>lastName</code> by assigning a value to <code>fullName</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> model = <span class="hljs-keyword">new</span> UserModel();

model.fullName = <span class="hljs-string">'Thomas Anderson'</span>;

<span class="hljs-built_in">console</span>.log(model.toJSON()); <span class="hljs-comment">// Output model fields as JSON</span>
<span class="hljs-built_in">console</span>.log();
<span class="hljs-built_in">console</span>.log(model.fullName); <span class="hljs-comment">// Output the full name</span>
</code></pre>
<p>The code above will output the following:</p>
<pre><code class="lang-bash">{ _id: 5a7a4248550ebb9fafd898cf,
  firstName: <span class="hljs-string">'Thomas'</span>,
  lastName: <span class="hljs-string">'Anderson'</span> }

Thomas Anderson
</code></pre>
<h4 id="heading-instance-methods">Instance Methods</h4>
<p>We can create custom helper methods on the schema and access them via the model instance. These methods will have access to the model object and they can be used quite creatively. For instance, we could create a method to find all the people who have the same first name as the current instance.</p>
<p>In this example, let’s create a function to return the initials for the current user. Let’s add a custom helper method called <code>getInitials</code> to the schema:</p>
<pre><code class="lang-js">userSchema.methods.getInitials = <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>.firstName[<span class="hljs-number">0</span>] + <span class="hljs-built_in">this</span>.lastName[<span class="hljs-number">0</span>];
};
</code></pre>
<p>This method will be accessible via a model instance:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> model = <span class="hljs-keyword">new</span> UserModel({
  <span class="hljs-attr">firstName</span>: <span class="hljs-string">'Thomas'</span>,
  <span class="hljs-attr">lastName</span>: <span class="hljs-string">'Anderson'</span>
});

<span class="hljs-keyword">let</span> initials = model.getInitials();

<span class="hljs-built_in">console</span>.log(initials); <span class="hljs-comment">// This will output: TA</span>
</code></pre>
<h4 id="heading-static-methods">Static Methods</h4>
<p>Similar to instance methods, we can create static methods on the schema. Let’s create a method to retrieve all users in the database:</p>
<pre><code class="lang-js">userSchema.statics.getUsers = <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-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-built_in">this</span>.find(<span class="hljs-function">(<span class="hljs-params">err, docs</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (err) {
        <span class="hljs-built_in">console</span>.error(err);
        <span class="hljs-keyword">return</span> reject(err);
      }

      resolve(docs);
    });
  });
};
</code></pre>
<p>Calling <code>getUsers</code> on the Model class will return all the users in the database:</p>
<pre><code class="lang-js">UserModel.getUsers()
  .then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(docs);
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(err);
  });
</code></pre>
<p>Adding instance and static methods is a nice approach to implement an interface to database interactions on collections and records.</p>
<h4 id="heading-middleware"><strong>Middleware</strong></h4>
<p>Middleware are functions that run at specific stages of a pipeline. Mongoose supports middleware for the following operations:</p>
<ul>
<li>Aggregate</li>
<li>Document</li>
<li>Model</li>
<li>Query</li>
</ul>
<p>For instance, models have <code>pre</code> and <code>post</code> functions that take two parameters:</p>
<ol>
<li>Type of event (‘init’, ‘validate’, ‘save’, ‘remove’)</li>
<li>A callback that is executed with <strong>this</strong> referencing the model instance</li>
</ol>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*iZwmyy25FSxuxXlH." alt="Image" width="800" height="310" loading="lazy">
<em>Example of Middleware (a.k.a. pre and post hooks)</em></p>
<p>Let’s try an example by adding two fields called <code>createdAt</code> and <code>updatedAt</code> to our schema:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);

<span class="hljs-keyword">let</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
  <span class="hljs-attr">firstName</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">lastName</span>: <span class="hljs-built_in">String</span>,
  <span class="hljs-attr">createdAt</span>: <span class="hljs-built_in">Date</span>,
  <span class="hljs-attr">updatedAt</span>: <span class="hljs-built_in">Date</span>
});

<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">'User'</span>, userSchema);
</code></pre>
<p>When <code>model.save()</code> is called, there is a <code>pre(‘save’, …)</code> and <code>post(‘save’, …)</code> event that is triggered. For the second parameter, you can pass a function that is called when the event is triggered. These functions take a parameter to the next function in the middleware chain.</p>
<p>Let’s add a pre-save hook and set values for <code>createdAt</code> and <code>updatedAt</code>:</p>
<pre><code class="lang-js">userSchema.pre(<span class="hljs-string">'save'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">next</span>) </span>{
  <span class="hljs-keyword">let</span> now = <span class="hljs-built_in">Date</span>.now();

  <span class="hljs-built_in">this</span>.updatedAt = now;
  <span class="hljs-comment">// Set a value for createdAt only if it is null</span>
  <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.createdAt) {
    <span class="hljs-built_in">this</span>.createdAt = now;
  }

  <span class="hljs-comment">// Call the next function in the pre-save chain</span>
  next();
});
</code></pre>
<p>Let’s create and save our model:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> UserModel = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./user'</span>);

<span class="hljs-keyword">let</span> model = <span class="hljs-keyword">new</span> UserModel({
  <span class="hljs-attr">fullName</span>: <span class="hljs-string">'Thomas Anderson'</span>
});

msg
  .save()
  .then(<span class="hljs-function">(<span class="hljs-params">doc</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(doc);
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(err);
  });
</code></pre>
<p>You should see values for <code>createdAt</code> and <code>updatedAt</code> when the record that is created is printed:</p>
<pre><code class="lang-json">{ _id: <span class="hljs-number">5</span>a7bbbeebc3b49cb919da675,
  firstName: 'Thomas',
  lastName: 'Anderson',
  updatedAt: <span class="hljs-number">2018</span><span class="hljs-number">-02</span><span class="hljs-number">-08</span>T02:<span class="hljs-number">54</span>:<span class="hljs-number">38.888</span>Z,
  createdAt: <span class="hljs-number">2018</span><span class="hljs-number">-02</span><span class="hljs-number">-08</span>T02:<span class="hljs-number">54</span>:<span class="hljs-number">38.888</span>Z,
  __v: <span class="hljs-number">0</span> }
</code></pre>
<h4 id="heading-plugins">Plugins</h4>
<p>Suppose that we want to track when a record was created and last updated on every collection in our database. Instead of repeating the above process, we can create a plugin and apply it to every schema.</p>
<p>Let’s create a file <code>./src/model/plugins/timestamp.js</code> and replicate the above functionality as a reusable module:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">timestamp</span>(<span class="hljs-params">schema</span>) </span>{
  <span class="hljs-comment">// Add the two fields to the schema</span>
  schema.add({
    <span class="hljs-attr">createdAt</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">updatedAt</span>: <span class="hljs-built_in">Date</span>
  });

  <span class="hljs-comment">// Create a pre-save hook</span>
  schema.pre(<span class="hljs-string">'save'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">next</span>) </span>{
    <span class="hljs-keyword">let</span> now = <span class="hljs-built_in">Date</span>.now();

    <span class="hljs-built_in">this</span>.updatedAt = now;
    <span class="hljs-comment">// Set a value for createdAt only if it is null</span>
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.createdAt) {
      <span class="hljs-built_in">this</span>.createdAt = now;
    }
    <span class="hljs-comment">// Call the next function in the pre-save chain</span>
    next();
  });
};
</code></pre>
<p>To use this plugin, we simply pass it to the schemas that should be given this functionality:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> timestampPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./plugins/timestamp'</span>);

emailSchema.plugin(timestampPlugin);
userSchema.plugin(timestampPlugin);
</code></pre>
<h3 id="heading-query-building">Query Building</h3>
<p>Mongoose has a very rich API that handles many complex operations supported by MongoDB. Consider a query where we can incrementally build query components.</p>
<p>In this example, we are going to:</p>
<ol>
<li>Find all users</li>
<li>Skip the first 100 records</li>
<li>Limit the results to 10 records</li>
<li>Sort the results by the firstName field</li>
<li>Select the firstName</li>
<li>Execute that query</li>
</ol>
<pre><code class="lang-js">UserModel.find()               <span class="hljs-comment">// find all users</span>
  .skip(<span class="hljs-number">100</span>)                   <span class="hljs-comment">// skip the first 100 items</span>
  .limit(<span class="hljs-number">10</span>)                   <span class="hljs-comment">// limit to 10 items</span>
  .sort({ <span class="hljs-attr">firstName</span>: <span class="hljs-number">1</span> })      <span class="hljs-comment">// sort ascending by firstName</span>
  .select({ <span class="hljs-attr">firstName</span>: <span class="hljs-literal">true</span> }) <span class="hljs-comment">// select firstName only</span>
  .exec()                      <span class="hljs-comment">// execute the query</span>
  .then(<span class="hljs-function">(<span class="hljs-params">docs</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(docs);
  })
  .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(err);
  });
</code></pre>
<h3 id="heading-closing">Closing</h3>
<p>We have barely scratched the surface exploring some of the capabilities of Mongoose. It is a rich library full of useful and and powerful features that make it a joy to work with data models in the application layer.</p>
<p>While you can interact with Mongo directly using Mongo Driver, Mongoose will simplify that interaction by allowing you to model relationships between data and validate them easily.</p>
<p><strong>Fun Fact:</strong> <a target="_blank" href="http://mongoosejs.com"><strong>Mongoose</strong></a> is created by <a target="_blank" href="https://www.freecodecamp.org/news/introduction-to-mongoose-for-mongodb-d2a7aa593c57/undefined"><strong>Valeri Karpov</strong></a> who is an incredibly talented engineer! He coined the term <a target="_blank" href="http://thecodebarbarian.com/2013/04/29//easy-web-prototyping-with-mongodb-and-nodejs"><strong>The MEAN Stack</strong></a>.</p>
<h4 id="heading-if-this-article-was-helpful-follow-me-on-twitterhttpstwittercomintentfollowscreennametheoutlander">If this article was helpful, <a target="_blank" href="https://twitter.com/intent/follow?screen_name=theoutlander">follow me on Twitter</a>.</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*278_8HmTEdaRAqFYUemQvQ.png" alt="Image" width="800" height="392" loading="lazy">
_[How to Build a REST API with Node | Express | Mongo](https://twitter.com/intent/follow?screen_name=theoutlander" rel="noopener" target="_blank" title=""&gt;You may also like my workshop on youtube: &lt;a href="https://youtu.be/egeHq-lYyxo" rel="noopener" target="<em>blank" title=")</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
