<olclass="chapter"><liclass="affix"><ahref="../index.html">Introduction</a></li><liclass="affix"><ahref="../quickstart.html">Quickstart</a></li><liclass="affix"><ahref="../types/index.html">Type System</a></li><li><ahref="../types/objects/defining_objects.html"><strongaria-hidden="true">1.</strong> Defining objects</a></li><li><olclass="section"><li><ahref="../types/objects/complex_fields.html"><strongaria-hidden="true">1.1.</strong> Complex fields</a></li><li><ahref="../types/objects/using_contexts.html"><strongaria-hidden="true">1.2.</strong> Using contexts</a></li><li><ahref="../types/objects/error_handling.html"><strongaria-hidden="true">1.3.</strong> Error handling</a></li></ol></li><li><ahref="../types/other-index.html"><strongaria-hidden="true">2.</strong> Other types</a></li><li><olclass="section"><li><ahref="../types/enums.html"><strongaria-hidden="true">2.1.</strong> Enums</a></li><li><ahref="../types/interfaces.html"><strongaria-hidden="true">2.2.</strong> Interfaces</a></li><li><ahref="../types/input_objects.html"><strongaria-hidden="true">2.3.</strong> Input objects</a></li><li><ahref="../types/scalars.html"><strongaria-hidden="true">2.4.</strong> Scalars</a></li><li><ahref="../types/unions.html"><strongaria-hidden="true">2.5.</strong> Unions</a></li></ol></li><li><ahref="../schema/schemas_and_mutations.html"><strongaria-hidden="true">3.</strong> Schemas and mutations</a></li><li><ahref="../servers/index.html"><strongaria-hidden="true">4.</strong> Adding A Server</a></li><li><olclass="section"><li><ahref="../servers/official.html"><strongaria-hidden="true">4.1.</strong> Official Server Integrations</a></li><li><olclass="section"><li><ahref="../servers/warp.html"><strongaria-hidden="true">4.1.1.</strong> Warp</a></li><li><ahref="../servers/rocket.html"><strongaria-hidden="true">4.1.2.</strong> Rocket</a></li><li><ahref="../servers/iron.html"><strongaria-hidden="true">4.1.3.</strong> Iron</a></li><li><ahref="../servers/hyper.html"><strongaria-hidden="true">4.1.4.</strong> Hyper</a></li></ol></li><li><ahref="../servers/third-party.html"><strongaria-hidden="true">4.2.</strong> Third Party Integrations</a></li></ol></li><li><ahref="../advanced/index.html"><strongaria-hidden="true">5.</strong> Advanced Topics</a></li><li><olclass="section"><li><ahref="../advanced/introspection.html"><strongaria-hidden="true">5.1.</strong> Introspection</a></li><li><ahref="../advanced/non_struct_objects.html"><strongaria-hidden="true">5.2.</strong> Non-struct objects</a></li><li><ahref="../advanced/objects_and_generics.html"><strongaria-hidden="true">5.3.</strong> Objects and generics</a></li><li><ahref="../advanced/multiple_ops_per_request.html"><strongaria-hidden="true">5.4.</strong> Multiple operations per request</a></li><li><ahref="../advanced/dataloaders.html"class="active"><strongaria-hidden="true">5.5.</strong> Dataloaders</a></li></ol></li></ol>
<buttonid="sidebar-toggle"class="icon-button"type="button"title="Toggle Table of Contents"aria-label="Toggle Table of Contents"aria-controls="sidebar">
<ahref="../print.html"title="Print this book"aria-label="Print this book">
<iid="print-button"class="fa fa-print"></i>
</a>
</div>
</div>
</div>
<divid="search-wrapper"class="hidden">
<formid="searchbar-outer"class="searchbar-outer">
<inputtype="search"name="search"id="searchbar"name="searchbar"placeholder="Search this book ..."aria-controls="searchresults-outer"aria-describedby="searchresults-header">
<aclass="header"href="#avoiding-the-n1-problem-with-dataloaders"id="avoiding-the-n1-problem-with-dataloaders"><h1>Avoiding the N+1 Problem With Dataloaders</h1></a>
<p>A common issue with graphql servers is how the resolvers query their datasource.
his issue results in a large number of unneccessary database queries or http requests.
Say you were wanting to list a bunch of cults people were in</p>
<pre><codeclass="language-graphql">query {
persons {
id
name
cult {
id
name
}
}
}
</code></pre>
<p>What would be executed by a SQL database would be:</p>
<pre><codeclass="language-sql">SELECT id, name, cult_id FROM persons;
SELECT id, name FROM cults WHERE id = 1;
SELECT id, name FROM cults WHERE id = 1;
SELECT id, name FROM cults WHERE id = 1;
SELECT id, name FROM cults WHERE id = 1;
SELECT id, name FROM cults WHERE id = 2;
SELECT id, name FROM cults WHERE id = 2;
SELECT id, name FROM cults WHERE id = 2;
# ...
</code></pre>
<p>Once the list of users has been returned, a separate query is run to find the cult of each user.
You can see how this could quickly become a problem.</p>
<p>A common solution to this is to introduce a <strong>dataloader</strong>.
This can be done with Juniper using the crate <ahref="https://github.com/cksac/dataloader-rs">cksac/dataloader-rs</a>, which has two types of dataloaders; cached and non-cached. This example will explore the non-cached option.</p>
<p>Once created, a dataloader has the functions <code>.load()</code> and <code>.load_many()</code>.
When called these return a Future.
In the above example <code>cult_loader.load(id: i32)</code> returns <code>Future<Cult></code>. If we had used <code>cult_loader.load_may(Vec<i32>)</code> it would have returned <code>Future<Vec<Cult>></code>.</p>
<p><strong>Dataloaders</strong> should be created per-request to avoid risk of bugs where one user is able to load cached/batched data from another user/ outside of its authenticated scope.
Creating dataloaders within individual resolvers will prevent batching from occurring and will nullify the benefits of the dataloader.</p>
<p>For a full example using Dataloaders and Context check out <ahref="https://github.com/jayy-lmao/rust-graphql-docker">jayy-lmao/rust-graphql-docker</a>.</p>