<?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" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Akshat Gupta on Medium]]></title>
        <description><![CDATA[Stories by Akshat Gupta on Medium]]></description>
        <link>https://medium.com/@akshatgupta1903?source=rss-abb58db856d9------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*RTYDzx1AL0OB57jTyOdYeA.jpeg</url>
            <title>Stories by Akshat Gupta on Medium</title>
            <link>https://medium.com/@akshatgupta1903?source=rss-abb58db856d9------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 03:45:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@akshatgupta1903/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Advanced Techniques with MongoDB: Mastering Lookup and Unwind]]></title>
            <link>https://medium.com/@akshatgupta1903/advanced-techniques-with-mongodb-mastering-lookup-and-unwind-acfc8a8ad5b9?source=rss-abb58db856d9------2</link>
            <guid isPermaLink="false">https://medium.com/p/acfc8a8ad5b9</guid>
            <category><![CDATA[mongodb]]></category>
            <category><![CDATA[aggregation]]></category>
            <category><![CDATA[database]]></category>
            <category><![CDATA[query-optimization]]></category>
            <dc:creator><![CDATA[Akshat Gupta]]></dc:creator>
            <pubDate>Sat, 28 Sep 2024 10:44:57 GMT</pubDate>
            <atom:updated>2024-09-28T10:44:57.358Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gf_XcvKMkfwiQLxTVqGiaA.png" /></figure><h3>Welcome to the World of MongoDB!</h3><p>Hey there! Before we dive into the nitty-gritty of MongoDB’s aggregation powers, let’s kick things off with a quick intro to what MongoDB is and why it’s such a big deal in the database world.</p><h4>What is MongoDB?</h4><p>MongoDB is a document-oriented NoSQL database that’s designed to handle large amounts of data at high speed. It’s all about giving developers flexibility and power to store and retrieve data in a way that’s intuitive and aligned with how developers actually think and code. Instead of tables and rows as in traditional relational databases, MongoDB works with collections and documents. This structure allows it to handle all sorts of data formats and to scale up easily, making it a favourite for everything from small startups to massive enterprises.</p><h4>Why MongoDB?</h4><ol><li><strong>Schema-less Nature</strong>: Each document in a collection can have a completely different structure. This flexibility means you can rapidly iterate and deploy new features without having to worry about restructuring your entire database.</li><li><strong>Scalability</strong>: MongoDB handles horizontal scaling with ease. You can spread your data across more servers easily as your app grows and attracts more users.</li><li><strong>Speed</strong>: Its indexing capabilities allow for fast queries, and its document model means that related data can be stored together and accessed quickly in a single query.</li></ol><p>So, whether you’re developing a new app, working on a complex data analysis task, or just trying to optimize your database, MongoDB offers a robust set of tools to make your life easier.</p><p>Now, let’s dive into some of the advanced features that truly show off what MongoDB can do when it comes to managing and querying your data. Buckle up; it’s going to be an enlightening ride!</p><h3>Introduction</h3><p>When working with MongoDB, understanding how to efficiently fetch and manipulate related data from multiple collections is crucial. To illustrate, let’s consider a simple eCommerce application that uses three main collections: customers, orders, and items.</p><blockquote>To try out all the queries discussed below use this <a href="https://mongoplayground.net/p/49cr94RYXVn">MongoDB Playground</a>. (Except for the populate query)</blockquote><h4>Schemas</h4><p>Customers Collection</p><ul><li><strong>_id</strong>: Unique identifier for each customer, an ObjectId.</li><li><strong>name</strong>: The customer’s name.</li><li><strong>email</strong>: The customer’s email address</li></ul><pre>[<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;cust100&quot;),<br>    &quot;name&quot;: &quot;Jane Doe&quot;,<br>    &quot;email&quot;: &quot;jane@example.com&quot;<br>  },<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;cust101&quot;),<br>    &quot;name&quot;: &quot;John Smith&quot;,<br>    &quot;email&quot;: &quot;john@example.com&quot;<br>  }<br>]</pre><p>Orders Collection</p><ul><li><strong>_id</strong>: Unique identifier for each order, an ObjectId.</li><li><strong>customerId</strong>: Reference to the customer’s ObjectId.</li><li><strong>itemIds</strong>: Array of item IDs purchased in this order.</li></ul><pre>[<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;ord200&quot;),<br>    &quot;customerId&quot;: ObjectId(&quot;cust100&quot;),<br>    &quot;itemIds&quot;: [ObjectId(&quot;item300&quot;), ObjectId(&quot;item301&quot;)]<br>  },<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;ord201&quot;),<br>    &quot;customerId&quot;: ObjectId(&quot;cust101&quot;),<br>    &quot;itemIds&quot;: [ObjectId(&quot;item302&quot;)]<br>  },<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;ord202&quot;),<br>    &quot;customerId&quot;: ObjectId(&quot;cust100&quot;),<br>    &quot;itemIds&quot;: [ObjectId(&quot;item301&quot;), ObjectId(&quot;item303&quot;)]<br>  }<br>]</pre><p>Items Collection</p><ul><li><strong>_id</strong>: Unique identifier for each item, an ObjectId.</li><li><strong>name</strong>: Name of the item.</li><li><strong>price</strong>: Price of the item.</li></ul><pre>[<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;item300&quot;),<br>    &quot;name&quot;: &quot;Bluetooth Speaker&quot;,<br>    &quot;price&quot;: 99.99<br>  },<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;item301&quot;),<br>    &quot;name&quot;: &quot;Wireless Mouse&quot;,<br>    &quot;price&quot;: 20.50<br>  },<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;item302&quot;),<br>    &quot;name&quot;: &quot;Keyboard&quot;,<br>    &quot;price&quot;: 45.00<br>  },<br>  {<br>    &quot;_id&quot;: ObjectId(&quot;item303&quot;),<br>    &quot;name&quot;: &quot;USB-C Charging Cable&quot;,<br>    &quot;price&quot;: 12.99<br>  }<br>]</pre><h4>Use Case 1: Viewing Orders with Customer Information</h4><p>Initially, you might want to view orders along with the information of the customer who placed them. Using Mongoose’s .populate method, you can easily replace the customerId with the actual customer document, enriching the orders with customer details. This is straightforward because the orders collection directly references the customer collection through the customerId.</p><pre>db.orders.find().populate(&#39;customerId&#39;);<br><br>[<br>  {<br>    &quot;_id&quot;: &quot;ord200&quot;,<br>    &quot;customerId&quot;: {<br>      &quot;_id&quot;: &quot;cust100&quot;,<br>      &quot;name&quot;: &quot;Jane Doe&quot;,<br>      &quot;email&quot;: &quot;jane@example.com&quot;<br>    },<br>    &quot;itemIds&quot;: [<br>      &quot;item300&quot;,<br>      &quot;item301&quot;<br>    ]<br>  },<br> ...<br>]</pre><h4>Use Case 2: Viewing Customers with Their Orders</h4><p>However, consider the reverse scenario: you want to see all customers along with a list of all orders they have placed. Here, the challenge arises because the customers schema does not inherently contain references to orders. Using .populate would not be possible directly, as it requires a reference within the document being queried.</p><p>This limitation illustrates a perfect scenario for using the $lookup operator from MongoDB’s aggregation framework. $lookup can perform a left outer join to the orders collection on the customerId field, effectively appending the matching orders to each customer document.</p><h3>Introducing the $lookup Operator</h3><blockquote><a href="https://www.mongodb.com/docs/manual/reference/operator/aggregation/lookup/">MongoDB Lookup Docs</a></blockquote><p>The $lookup stage in MongoDB&#39;s aggregation pipeline is a powerful tool that performs a left outer join to another collection within the same database. This capability is crucial for enriching documents with data from related collections and provides a versatile alternative to simpler methods like Mongoose’s .populate.</p><p>Knowing the existence of this powerful tool, let’s try to now solve the above Use Case 2 using $lookup .</p><pre>db.customers.aggregate([<br>  {<br>    $lookup: {<br>      from: &quot;orders&quot;,               // The collection to join.<br>      localField: &quot;_id&quot;,            // The field from the customers collection.<br>      foreignField: &quot;customerId&quot;,   // The field from the orders collection.<br>      as: &quot;orders&quot;                  // The output array containing joined documents.<br>    }<br>  }<br>]);<br><br>[<br>  {<br>    &quot;_id&quot;: &quot;cust100&quot;,<br>    &quot;email&quot;: &quot;jane@example.com&quot;,<br>    &quot;name&quot;: &quot;Jane Doe&quot;,<br>    &quot;orders&quot;: [<br>      {<br>        &quot;_id&quot;: &quot;ord200&quot;,<br>        &quot;customerId&quot;: &quot;cust100&quot;,<br>        &quot;itemIds&quot;: [<br>          &quot;item300&quot;,<br>          &quot;item301&quot;<br>        ]<br>      },<br>      {<br>        &quot;_id&quot;: &quot;ord202&quot;,<br>        &quot;customerId&quot;: &quot;cust100&quot;,<br>        &quot;itemIds&quot;: [<br>          &quot;item301&quot;,<br>          &quot;item303&quot;<br>        ]<br>      }<br>    ]<br>  },<br>  ...<br>]</pre><h4>$lookup with Pipeline for Deep Population</h4><p>To enhance the depth of our aggregation queries further, let’s address the remaining limitation where the itemIds in the orders are still showing as ObjectIds instead of being populated with item details. We can achieve this by using a nested $lookup within an existing $lookup—essentially a lookup inside another lookup.</p><p>Using the pipeline option within $lookup, we can execute a more complex query that not only joins documents but also allows for operations like matching and projecting within the nested $lookup. This method is perfect for fetching detailed item data within each order.</p><pre>db.customers.aggregate([<br>  {<br>    $lookup: {<br>      from: &quot;orders&quot;,<br>      let: { customer_id: &quot;$_id&quot; }, // Define the local variable to use in the pipeline<br>      pipeline: [<br>        { $match: { $expr: { $eq: [&quot;$customerId&quot;, &quot;$$customer_id&quot;] } } },<br>        { $lookup: {<br>          from: &quot;items&quot;,<br>          let: { order_item_ids: &quot;$itemIds&quot; },<br>          pipeline: [<br>            { $match: { $expr: { $in: [&quot;$_id&quot;, &quot;$$order_item_ids&quot;] } } } // Match items from the order&#39;s itemIds<br>          ],<br>          as: &quot;items&quot;<br>        }}<br>      ],<br>      as: &quot;orders&quot;<br>    }<br>  }<br>]);<br><br>[<br>  {<br>    &quot;_id&quot;: &quot;cust100&quot;,<br>    &quot;email&quot;: &quot;jane@example.com&quot;,<br>    &quot;name&quot;: &quot;Jane Doe&quot;,<br>    &quot;orders&quot;: [<br>      {<br>        &quot;_id&quot;: &quot;ord200&quot;,<br>        &quot;customerId&quot;: &quot;cust100&quot;,<br>        &quot;itemIds&quot;: [<br>          &quot;item300&quot;,<br>          &quot;item301&quot;<br>        ],<br>        &quot;items&quot;: [<br>          {<br>            &quot;_id&quot;: &quot;item300&quot;,<br>            &quot;name&quot;: &quot;Bluetooth Speaker&quot;,<br>            &quot;price&quot;: 99.99<br>          },<br>          {<br>            &quot;_id&quot;: &quot;item301&quot;,<br>            &quot;name&quot;: &quot;Wireless Mouse&quot;,<br>            &quot;price&quot;: 20.5<br>          }<br>        ]<br>      },<br>      {<br>        &quot;_id&quot;: &quot;ord202&quot;,<br>        &quot;customerId&quot;: &quot;cust100&quot;,<br>        &quot;itemIds&quot;: [<br>          &quot;item301&quot;,<br>          &quot;item303&quot;<br>        ],<br>        &quot;items&quot;: [<br>          {<br>            &quot;_id&quot;: &quot;item301&quot;,<br>            &quot;name&quot;: &quot;Wireless Mouse&quot;,<br>            &quot;price&quot;: 20.5<br>          },<br>          {<br>            &quot;_id&quot;: &quot;item303&quot;,<br>            &quot;name&quot;: &quot;USB-C Charging Cable&quot;,<br>            &quot;price&quot;: 12.99<br>          }<br>        ]<br>      }<br>    ]<br>  },<br>  ...<br>]</pre><p>Using nested $lookup operations with the pipeline option allows for much more sophisticated queries, including conditions and transformations within each join. This method is especially useful for deeply nested data structures or when multiple collections must be joined with specific conditions. It also makes the aggregation process more efficient by reducing the amount of data processed in each stage by applying filters early in the pipeline.</p><h3>Introducing the $unwind Operator</h3><blockquote><a href="https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind/"><em>MongoDB Unwind Docs</em></a></blockquote><p>The $unwind stage in MongoDB&#39;s aggregation pipeline is used to deconstruct an array field from the input documents to output a document for each element. Each output document is the input document with the value of the array field replaced by the element. This is particularly useful when operations such as grouping or calculating aggregates on array elements are needed.</p><p>Consider a scenario where a business wants to analyse the total sales for each item across all orders, potentially to assess which items are best sellers. To accomplish this, we must first flatten the items array that we enriched in the previous section using $lookup. After unwinding, we can then group by item and sum up quantities or calculate total sales.</p><pre>db.orders.aggregate([<br>  {<br>    $lookup: {<br>      from: &quot;items&quot;,<br>      localField: &quot;itemIds&quot;,<br>      foreignField: &quot;_id&quot;,<br>      as: &quot;itemDetails&quot;<br>    }<br>  },<br>  { $unwind: &quot;$itemDetails&quot; },<br>  {<br>    $group: {<br>      _id: &quot;$itemDetails._id&quot;,<br>      name: { $first: &quot;$itemDetails.name&quot; },<br>      totalSales: { $sum: &quot;$itemDetails.price&quot; }<br>    }<br>  }<br>]);<br><br>[<br>  {<br>    &quot;_id&quot;: &quot;item300&quot;,<br>    &quot;name&quot;: &quot;Bluetooth Speaker&quot;,<br>    &quot;totalSales&quot;: 99.99<br>  },<br>  ...<br>]</pre><p>To explore a more complex scenario involving all three collections (customers, orders, and items), let&#39;s consider a business use case where we want to generate detailed sales reports for each customer. This report will include the total amount spent by each customer, detailed by each item they&#39;ve purchased, reflecting the quantities and total prices.</p><pre>db.customers.aggregate([<br>  {<br>    $lookup: {<br>      from: &quot;orders&quot;,<br>      localField: &quot;_id&quot;,<br>      foreignField: &quot;customerId&quot;,<br>      as: &quot;orders&quot;<br>    }<br>  },<br>  {<br>    $unwind: &quot;$orders&quot;<br>  },<br>  {<br>    $lookup: {<br>      from: &quot;items&quot;,<br>      localField: &quot;orders.itemIds&quot;,<br>      foreignField: &quot;_id&quot;,<br>      as: &quot;orders.items&quot;<br>    }<br>  },<br>  {<br>    $unwind: &quot;$orders.items&quot;<br>  },<br>  {<br>    $group: {<br>      _id: {<br>        customerId: &quot;$_id&quot;,<br>        orderId: &quot;$orders._id&quot;<br>      },<br>      customerName: {<br>        $first: &quot;$name&quot;<br>      },<br>      customerEmail: {<br>        $first: &quot;$email&quot;<br>      },<br>      items: {<br>        $push: {<br>          itemId: &quot;$orders.items._id&quot;,<br>          itemName: &quot;$orders.items.name&quot;,<br>          itemPrice: &quot;$orders.items.price&quot;<br>        }<br>      },<br>      orderTotal: {<br>        $sum: &quot;$orders.items.price&quot;<br>      }<br>    }<br>  },<br>  {<br>    $group: {<br>      _id: &quot;$_id.customerId&quot;,<br>      name: {<br>        $first: &quot;$customerName&quot;<br>      },<br>      email: {<br>        $first: &quot;$customerEmail&quot;<br>      },<br>      orders: {<br>        $push: {<br>          orderId: &quot;$_id.orderId&quot;,<br>          items: &quot;$items&quot;,<br>          total: &quot;$orderTotal&quot;<br>        }<br>      },<br>      totalSpent: {<br>        $sum: &quot;$orderTotal&quot;<br>      }<br>    }<br>  }<br>]);<br><br>[<br>  {<br>    &quot;_id&quot;: &quot;cust100&quot;,<br>    &quot;email&quot;: &quot;jane@example.com&quot;,<br>    &quot;name&quot;: &quot;Jane Doe&quot;,<br>    &quot;orders&quot;: [<br>      {<br>        &quot;items&quot;: [<br>          {<br>            &quot;itemId&quot;: &quot;item300&quot;,<br>            &quot;itemName&quot;: &quot;Bluetooth Speaker&quot;,<br>            &quot;itemPrice&quot;: 99.99<br>          },<br>          {<br>            &quot;itemId&quot;: &quot;item301&quot;,<br>            &quot;itemName&quot;: &quot;Wireless Mouse&quot;,<br>            &quot;itemPrice&quot;: 20.5<br>          }<br>        ],<br>        &quot;orderId&quot;: &quot;ord200&quot;,<br>        &quot;total&quot;: 120.49<br>      },<br>      {<br>        &quot;items&quot;: [<br>          {<br>            &quot;itemId&quot;: &quot;item301&quot;,<br>            &quot;itemName&quot;: &quot;Wireless Mouse&quot;,<br>            &quot;itemPrice&quot;: 20.5<br>          },<br>          {<br>            &quot;itemId&quot;: &quot;item303&quot;,<br>            &quot;itemName&quot;: &quot;USB-C Charging Cable&quot;,<br>            &quot;itemPrice&quot;: 12.99<br>          }<br>        ],<br>        &quot;orderId&quot;: &quot;ord202&quot;,<br>        &quot;total&quot;: 33.49<br>      }<br>    ],<br>    &quot;totalSpent&quot;: 153.98<br>  },<br>  ...<br>]</pre><h3>Bonus Section: Optimising MongoDB Queries</h3><p>Thank you for following along with our in-depth exploration of MongoDB’s powerful aggregation framework! Your willingness to dive deep into these complex queries will surely enhance your skills in managing and querying MongoDB databases. As a token of appreciation, here are two essential tips that can help optimise your MongoDB queries, especially when working with complex data models involving multiple lookups and unwinds.</p><p><strong>1. Applying Proper Indexing to Improve Query Speed</strong></p><blockquote><a href="https://www.mongodb.com/docs/manual/indexes/"><em>MongoDB Indexing Docs</em></a></blockquote><p><strong>Indexing</strong> is a critical factor in enhancing the performance of database operations. In MongoDB, indexes support the efficient execution of queries. Without indexes, MongoDB must perform a collection scan, which scans every document in a collection, to select those documents that match the query statement. Here’s how proper indexing can help:</p><ul><li><strong>Targeted Indexing</strong>: Ensure that fields used in $match, $sort, and $group stages of your queries are indexed. MongoDB uses these indexes to quickly locate and retrieve the data without scanning every document.</li><li><strong>Compound Indexes</strong>: When multiple fields are used in query conditions, consider creating a compound index that includes these fields. MongoDB can then use this single index to fulfill complex queries efficiently.</li><li><strong>Index Usage in </strong><strong>$lookup</strong>: For operations that use the $lookup stage, indexing the foreign field can drastically improve the performance, as MongoDB can use the index to quickly perform the join operation.</li></ul><p><strong>2. Optimising Queries with Strategic Ordering of </strong><strong>$lookup and </strong><strong>$unwind</strong></p><p>When your queries involve multiple $lookup and $unwind operations, the order in which you place these operations can significantly impact performance:</p><ul><li><strong>Minimise Early Unwinds</strong>: Avoid using $unwind at an early stage in your aggregation pipeline. The $unwind operation can significantly increase the number of documents processed by subsequent stages. If possible, filter your data using $match or reduce the dataset with $group before you apply $unwind.</li><li><strong>Ordering Lookups:</strong> When applying multiple $lookup, make sure you perform lookups on array field at the last and if possible, based on your use case only apply unwinds after all the lookups have been performed. This will prevent redundant lookups performed for the unwinded array objects.</li><li><strong>Filter Before Join</strong>: Apply $match operations to filter data as much as possible before performing a $lookup. This reduces the amount of data that needs to be joined and can prevent unnecessary processing.</li><li><strong>Nested </strong><strong>$lookup Optimisation</strong>: When using nested $lookup, ensure that the inner lookup only processes the necessary documents. Use the let and pipeline options in $lookup to apply conditions that reduce the number of documents that need to be joined.</li></ul><p><strong>Suboptimal Query Structure</strong></p><p>Here’s a version of the query where we first join and unwind items, followed by a join on customers, which could lead to redundant operations:</p><pre>db.orders.aggregate([<br>  {<br>    $lookup: {<br>      from: &quot;items&quot;,<br>      localField: &quot;itemIds&quot;,<br>      foreignField: &quot;_id&quot;,<br>      as: &quot;itemDetails&quot;<br>    }<br>  },<br>  { $unwind: &quot;$itemDetails&quot; },  // Unwinding early increases the document count<br>  {<br>    $lookup: {<br>      from: &quot;customers&quot;,<br>      localField: &quot;customerId&quot;,<br>      foreignField: &quot;_id&quot;,<br>      as: &quot;customerDetails&quot;<br>    }<br>  }<br>]);</pre><p>In this structure:</p><ul><li>Each order is first joined with the items collection, potentially multiplying the number of documents if orders contain multiple items.</li><li>After unwinding the items, the number of documents may increase significantly — each document now represents an order with exactly one item.</li><li>A subsequent $lookup on customers is applied to each of these unwound documents. If the initial order contained 5 items, and there were 100 such orders, after unwinding, we&#39;re performing the $lookup on 500 documents.</li></ul><p><strong>Optimised Query Structure</strong></p><p>A more efficient approach would be to first join customers and then join and unwind items, as shown below:</p><pre>db.orders.aggregate([<br>  {<br>    $lookup: {<br>      from: &quot;customers&quot;,<br>      localField: &quot;customerId&quot;,<br>      foreignField: &quot;_id&quot;,<br>      as: &quot;customerDetails&quot;<br>    }<br>  },<br>  {<br>    $lookup: {<br>      from: &quot;items&quot;,<br>      localField: &quot;itemIds&quot;,<br>      foreignField: &quot;_id&quot;,<br>      as: &quot;itemDetails&quot;<br>    }<br>  },<br>  { $unwind: &quot;$itemDetails&quot; }  // Unwind after all lookups<br>]);</pre><p>In this optimised structure:</p><ul><li>Each order is first joined with the customers collection, which does not increase the number of documents—each order still corresponds to one document.</li><li>Only after all orders have customer details attached do we perform the $lookup on items.</li><li>Unwinding the items now does not affect the performance of joining customers, as it happens afterward.</li></ul><h3>That’s a Wrap — Thanks for Sticking With Me!</h3><p>We’ve finally hit the end of our deep dive into some of the cooler parts of MongoDB, and I just want to say thanks for nerding out with me. It’s been a real treat to unpack all these tricky bits like nested $lookups and getting the most out of $unwind.</p><p>Catch you later, and keep on querying!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=acfc8a8ad5b9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Register, Login and Logout in Django Rest Framework using JWT]]></title>
            <link>https://medium.com/mozilla-firefox-club/register-login-and-logout-in-django-rest-framework-using-jwt-a49963dfddce?source=rss-abb58db856d9------2</link>
            <guid isPermaLink="false">https://medium.com/p/a49963dfddce</guid>
            <category><![CDATA[authentication]]></category>
            <category><![CDATA[mozilla]]></category>
            <category><![CDATA[mfcvit]]></category>
            <category><![CDATA[jwt]]></category>
            <category><![CDATA[django]]></category>
            <dc:creator><![CDATA[Akshat Gupta]]></dc:creator>
            <pubDate>Sun, 07 Feb 2021 07:55:21 GMT</pubDate>
            <atom:updated>2021-02-07T08:41:17.575Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*CXPMbCsb_irrhxZN.png" /></figure><p>In this tutorial we will learn how to use <strong>JWT (JSON Web Tokens)</strong> to create register, login and logout views in <strong>Django Rest framework (DRF)</strong>.</p><p>We will use two tokens in this tutorial <strong>Refresh Token</strong> and <strong>Access Token</strong>. The client side server will store both the tokens and use them to send a request to an API endpoint which requires authentication of the user. When the user sends the login request with his credentials they get in return the two above mentioned two tokens which they need to store in their session. Now to access any end point which requires user authentication they need to send their access token in the request header, but then whats the use of Refresh token?</p><p>As the name suggests <strong>Refresh Token</strong> is like a refresh button which is used to refresh the Access Token, we will discuss it in detail when we will create User Logout view but for the time being just know that Access Token is very short lived and gets expired after certain time and to get the new token user needs to request it using refresh token.</p><p>Let’s first install the required packages —</p><pre>pip install djangorestframework<br>pip install djangorestframework-simplejwt</pre><p>Now let’s set up the settings.py file now and make the following changes in it</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6f29d6adb96e6b8edff15b190b05cc91/href">https://medium.com/media/6f29d6adb96e6b8edff15b190b05cc91/href</a></iframe><p>Now let’s start by first extending the <strong>User model</strong> to create tokens.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6165ac4f4958d692002816d1a93124fb/href">https://medium.com/media/6165ac4f4958d692002816d1a93124fb/href</a></iframe><p>In this user model we created a function <strong>tokens</strong> to assign the user with Refresh and Access Tokens.</p><p>Now let’s create the serializers for Register, Login and Logout.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/138b86f36f3c45345a207fff4ebd5ebf/href">https://medium.com/media/138b86f36f3c45345a207fff4ebd5ebf/href</a></iframe><p>Let’s try to understand these serializers in detail starting from RegisterSerializer.</p><p>In <strong>RegisterSerializer</strong> we set the password field to <em>write only</em> so that the user can’t see that in the request sent, then we accept fields - email, username and password to register the user. We then create a <em>validate method</em> to validate the username and then the final <em>create method</em> to create the user with the provided details.</p><p>In <strong>LoginSerializer</strong> we again set the password field to <em>write only</em> so that the user cant see that in the request sent. Then we need a method <strong>get_tokens </strong>which in returns call the method <strong>tokens </strong>from <em>User model</em> to get the tokens for the user that’s trying to send the login request to our API. After that we create a method to check whether the user provided correct username and password and if yes then return him the details with the <strong>Access</strong> and <strong>Refresh Tokens</strong>.</p><p>After the user gets tokens he can send request to any API endpoint that requires user authentication by adding access token in headers and in case the token expires we request a new token by using refresh token which we will see when we will create <em>urls</em> file.</p><p>Coming to the logout view which is a bit tricky we need to understand that we need to keep the <strong>JWT</strong> stateless, in simple words the authentication details are stored on client side and not on server side so we need to somehow blacklist those details/tokens so that the user can’t use them again after logging out.</p><p>To do that we use a <strong>Simple JWT blacklist</strong> option that blacklists the refresh token so that it can not be used again. Now you may be wondering that why only refresh tokens when the actual token we use for authentication is <em>access</em> <em>token</em>? The answer to that is as I already said the beginning that access token is very short lived in fact every time you need to send request to an endpoint you will need to get the new access token. So whats the better way to blacklist the refresh token itself so that the user cant request for new access token in other words user successfully logged out <em>booyaaahhh!!!!</em>.</p><p>Now all the heavy work is almost done we just need to create the <em>views</em> and <em>urls</em> and we are done. So let’s create views first —</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5de8d7ec65e3a801089c170fbc5a40ac/href">https://medium.com/media/5de8d7ec65e3a801089c170fbc5a40ac/href</a></iframe><p>Just link the serializers to the respective views, call the methods and we are done with views as all the heavy lifting was already done in serializers file.</p><p>Now lets assign these <em>views</em> to the <em>urls</em>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8bb398ccb500d114340583ccaa1e6b87/href">https://medium.com/media/8bb398ccb500d114340583ccaa1e6b87/href</a></iframe><p>We link the <em>views</em> to their respective <em>urls</em> but notice the <strong>token_refresh </strong>url, as I mentioned earlier about the refresh token, Simple JWT provide a predefined <strong>TokenRefreshView </strong>which we can directly use and all the heavy lifting is already done for us!! isn’t <strong>DRF</strong> just simply awesome 😜.</p><p>Now its time to finally test our API so just run our own home sweet home localserver <em>127.0.0.1</em>, oh wait there’s command for that too in <strong>django</strong> 😜 just run</p><pre>python manage.py runserver</pre><p>Open your postman and lets check our endpoints.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WhRvkh5tBDds5heanAsZEA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_KWws0Qhhls4sxy0BWQaqA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jWeQ600edOdiKerDUZNuug.png" /></figure><p>So our task is complete here, you can now import this app in any of your projects which requires <strong>Login</strong>, <strong>Logout</strong> and <strong>Registration</strong> of the user.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a49963dfddce" width="1" height="1" alt=""><hr><p><a href="https://medium.com/mozilla-firefox-club/register-login-and-logout-in-django-rest-framework-using-jwt-a49963dfddce">Register, Login and Logout in Django Rest Framework using JWT</a> was originally published in <a href="https://medium.com/mozilla-firefox-club">Mozilla Firefox Club VIT Vellore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>