<?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[ Batch Loading - 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[ Batch Loading - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 22:21:22 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/batch-loading/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to optimize your queries to solve common scalability bottlenecks in Rails ]]>
                </title>
                <description>
                    <![CDATA[ By Usama Ashraf The (perfect) solution for the N+1 problem The n+1 query problem is one of the most common scalability bottlenecks. It involves fetching a list of resources from a database that includes other associated resources within them. This m... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/n-1-queries-batch-loading-active-model-serializers-in-rails-72662d7736f1/</link>
                <guid isPermaLink="false">66c35bd9c337fbd10a4b591e</guid>
                
                    <category>
                        <![CDATA[ Batch Loading ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rails ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 04 Mar 2018 19:18:58 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*Ph_m9KGrsfJPHGwpfXA8nQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Usama Ashraf</p>
<h4 id="heading-the-perfect-solution-for-the-n1-problem">The (perfect) solution for the N+1 problem</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Csu1xKKjVyRarXO3zKOQi-PwvPuR750NjwYt" alt="Image" width="800" height="343" loading="lazy"></p>
<p>The n+1 query problem is one of the most common scalability bottlenecks. It involves fetching a list of resources from a database that includes other associated resources within them. This means that we might have to query for the associated resources separately. So if you have a list of n parent objects, <em>another n queries will have to be executed for fetching the associated resources</em>. Let’s try to get rid of this O(n) conundrum.</p>
<p>If you’re comfortable with Rails, <a target="_blank" href="https://github.com/rails-api/active_model_serializers">Active Model Serializers</a>, and already have a good idea about what our problem is going to be, then maybe you can jump straight into the code <a target="_blank" href="https://gist.github.com/UsamaAshraf/95b0c8d0d64ee193148342a931c0a423">here</a>.</p>
<h4 id="heading-a-concrete-example">A Concrete Example</h4>
<p>Say you’re fetching an array of <strong>Post</strong> objects at a GET endpoint. You also want to load the respective authors of the posts, embedding an <strong>author</strong> object within each of the post objects. Here’s a naive way of doing it:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostsController</span> &lt; <span class="hljs-title">ApplicationController</span>    <span class="hljs-title">def</span> <span class="hljs-title">index</span>        <span class="hljs-title">posts</span> </span>= Post.all              render json: posts    endend
</code></pre><pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span>  <span class="hljs-title">belongs_to</span> :<span class="hljs-title">author</span>, <span class="hljs-title">class_name</span>: '<span class="hljs-title">User</span>'<span class="hljs-title">end</span></span>
</code></pre><pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostSerializer</span> &lt; <span class="hljs-title">ActiveModel</span>::<span class="hljs-title">Serializer</span>    <span class="hljs-title">attributes</span> :<span class="hljs-title">id</span>, :<span class="hljs-title">title</span>, :<span class="hljs-title">details</span></span>
</code></pre><pre><code>  belongs_to :author end
</code></pre><p>For each of the n <strong>Post</strong> objects being rendered, a query will run to fetch the corresponding <strong>User</strong> object. Hence we’ll run a total of n+1 queries. This is disastrous. And here’s how you fix it by eager loading the <strong>User</strong> object:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostsController</span> &lt; <span class="hljs-title">ApplicationController</span>    <span class="hljs-title">def</span> <span class="hljs-title">index</span>        # <span class="hljs-title">Runs</span> <span class="hljs-title">a</span> <span class="hljs-title">SQL</span> <span class="hljs-title">join</span> <span class="hljs-title">with</span> <span class="hljs-title">the</span> <span class="hljs-title">users</span> <span class="hljs-title">table</span>.    <span class="hljs-title">posts</span> </span>= Post.includes(:author).all              render json: posts    endend
</code></pre><h4 id="heading-when-a-simple-join-is-not-possible">When A Simple Join Is Not Possible</h4>
<p>Until now there’s been absolutely nothing new for veterans.</p>
<p>But let’s complicate this. <em>Let’s assume that the site’s users are not being stored in the same RDMS as the posts are. Rather, the users are documents stored in MongoDB (for whatever reason).</em> How do we modify our <strong>Post</strong> serializer to fetch the user now, optimally? This would be going back to square one:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostSerializer</span> &lt; <span class="hljs-title">ActiveModel</span>::<span class="hljs-title">Serializer</span>    <span class="hljs-title">attributes</span> :<span class="hljs-title">id</span>, :<span class="hljs-title">title</span>, :<span class="hljs-title">details</span>, :<span class="hljs-title">author</span></span>
</code></pre><pre><code>  # Will run n Mongo queries <span class="hljs-keyword">for</span> n posts being rendered.  def author    User.find(object.author_id)  endend
</code></pre><pre><code># This is now a Mongoid <span class="hljs-built_in">document</span>, not an ActiveRecord model.class User    include Mongoid::Document    include Mongoid::Timestamps    # ...end
</code></pre><p>The predicament that our users now reside in a Mongo database can be substituted with, say, calling a 3rd party HTTP service for fetching the users or storing them in a completely different RDMS. <em>Our essential problem remains that there’s no way to ‘join’ the users datastore with the posts table and get the response we want in a single query.</em></p>
<p>Of course, we can do better. We can fetch the entire response in two queries:</p>
<ul>
<li>Fetch all the posts without the <strong>author</strong> attribute (1 SQL query).</li>
<li>Fetch all the corresponding authors by running a where-in query with the user IDs plucked from the array of posts (1 Mongo query with an IN clause).</li>
</ul>
<pre><code>posts      = Post.allauthor_ids = posts.pluck(:author_id)authors    = User.where(:_id.in =&gt; author_ids)
</code></pre><pre><code># Somehow pass the author objects to the post serializer and# map them to the correct post objects. Can<span class="hljs-string">'t imagine what # exactly that would look like, but probably not pretty.render json: posts, pass_some_parameter_maybe: authors</span>
</code></pre><h4 id="heading-enter-batch-loader">Enter Batch Loader</h4>
<p>So our original optimization problem has been reduced to “how do we make this code readable and maintainable”. The folks at <a target="_blank" href="https://www.universe.com/about">Universe</a> have come up with an absolute gem (too obvious?). <a target="_blank" href="https://github.com/exAspArk/batch-loader">Batch Loader</a> has been incredibly helpful to me recently.</p>
<p><code>gem 'batch-loader'</code></p>
<p><code>bundle install</code></p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostSerializer</span> &lt; <span class="hljs-title">ActiveModel</span>::<span class="hljs-title">Serializer</span>    <span class="hljs-title">attributes</span> :<span class="hljs-title">id</span>, :<span class="hljs-title">title</span>, :<span class="hljs-title">details</span>, :<span class="hljs-title">author</span></span>
</code></pre><pre><code>  def author    object.get_author_lazily  endend
</code></pre><pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span>  <span class="hljs-title">def</span> <span class="hljs-title">get_author_lazily</span>    # <span class="hljs-title">The</span> <span class="hljs-title">current</span> <span class="hljs-title">post</span> <span class="hljs-title">object</span> <span class="hljs-title">is</span> <span class="hljs-title">added</span> <span class="hljs-title">to</span> <span class="hljs-title">the</span> <span class="hljs-title">batch</span> <span class="hljs-title">here</span>,    # <span class="hljs-title">which</span> <span class="hljs-title">is</span> <span class="hljs-title">eventually</span> <span class="hljs-title">processed</span> <span class="hljs-title">when</span> <span class="hljs-title">the</span> <span class="hljs-title">block</span> <span class="hljs-title">executes</span>.       <span class="hljs-title">BatchLoader</span>.<span class="hljs-title">for</span>(<span class="hljs-title">self</span>).<span class="hljs-title">batch</span> <span class="hljs-title">do</span> |<span class="hljs-title">posts</span>, <span class="hljs-title">batch_loader</span>|</span>
</code></pre><pre><code>      author_ids = posts.pluck(:author_id)        User.where(:_id.in =&gt; author_ids).each <span class="hljs-keyword">do</span> |user|        post = posts.detect { |p| p.author_id == user._id.to_s }        #<span class="hljs-string">'Assign'</span> the user object to the right post.        batch_loader.call(post, user)            end        end    endend
</code></pre><p>If you’re familiar with JavaScript Promises, think of the <code>get_author_lazily</code> method as returning a Promise which is evaluated later. That’s a decent analogy, I think since <code>BatchLoader</code> uses <a target="_blank" href="https://ruby-doc.org/core-2.4.1/Enumerable.html#method-i-lazy">lazy Ruby objects</a>. By default, <code>BatchLoader</code> caches the loaded values, and so to keep the responses up-to-date you should add this to your <code>config/application.rb</code>:</p>
<pre><code>config.middleware.use BatchLoader::Middleware
</code></pre><p>That’s it! We’ve solved an advanced version of the n+1 queries problem while keeping our code clean and using Active Model Serializers the right way.</p>
<h4 id="heading-using-ams-for-nested-resources">Using AMS for Nested Resources</h4>
<p>One problem though. If you have a <strong>User</strong> serializer (Active Model Serializers work with Mongoid as well), that <em>won’t</em> be called for the lazily loaded <strong>author</strong> objects, unlike before. To fix this, we can use a Ruby block and serialize the <strong>author</strong> objects before they’re ‘assigned’ to the posts.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostSerializer</span> &lt; <span class="hljs-title">ActiveModel</span>::<span class="hljs-title">Serializer</span>    <span class="hljs-title">attributes</span> :<span class="hljs-title">id</span>, :<span class="hljs-title">title</span>, :<span class="hljs-title">details</span>, :<span class="hljs-title">author</span></span>
</code></pre><pre><code>  def author    object.get_author_lazily <span class="hljs-keyword">do</span> |author|      # Serialize the author after it has been loaded.           ActiveModelSerializers::SerializableResource                             .new(author)                             .as_json[:user]    end  endend
</code></pre><pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span>  <span class="hljs-title">def</span> <span class="hljs-title">get_author_lazily</span>    # <span class="hljs-title">The</span> <span class="hljs-title">current</span> <span class="hljs-title">post</span> <span class="hljs-title">object</span> <span class="hljs-title">is</span> <span class="hljs-title">added</span> <span class="hljs-title">to</span> <span class="hljs-title">the</span> <span class="hljs-title">batch</span> <span class="hljs-title">here</span>,    # <span class="hljs-title">which</span> <span class="hljs-title">is</span> <span class="hljs-title">eventually</span> <span class="hljs-title">processed</span> <span class="hljs-title">when</span> <span class="hljs-title">the</span> <span class="hljs-title">block</span> <span class="hljs-title">executes</span>.       <span class="hljs-title">BatchLoader</span>.<span class="hljs-title">for</span>(<span class="hljs-title">self</span>).<span class="hljs-title">batch</span> <span class="hljs-title">do</span> |<span class="hljs-title">posts</span>, <span class="hljs-title">batch_loader</span>|</span>
</code></pre><pre><code>      author_ids = posts.pluck(:author_id)      User.where(:_id.in =&gt; author_ids).each <span class="hljs-keyword">do</span> |user|        modified_user = block_given? ? <span class="hljs-keyword">yield</span>(user) : user        post = posts.detect { |p| p.author_id == user._id.to_s }          # <span class="hljs-string">'Assign'</span> the user object to the right post.        batch_loader.call(post, modified_user)            end        end    endend
</code></pre><p><a target="_blank" href="https://gist.github.com/UsamaAshraf/95b0c8d0d64ee193148342a931c0a423">Here’s</a> the entire code. Enjoy!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
