<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shubham Ravani</title>
    <description>The latest articles on DEV Community by Shubham Ravani (@shubham_ravani).</description>
    <link>https://dev.to/shubham_ravani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3698086%2Fdc804a5b-6c20-478f-9797-7c205bf0aef7.png</url>
      <title>DEV Community: Shubham Ravani</title>
      <link>https://dev.to/shubham_ravani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shubham_ravani"/>
    <language>en</language>
    <item>
      <title>MongoDB Indexing Guidelines: Why Your Index Exists but Is Never Used</title>
      <dc:creator>Shubham Ravani</dc:creator>
      <pubDate>Wed, 07 Jan 2026 11:29:53 +0000</pubDate>
      <link>https://dev.to/shubham_ravani/mongodb-indexing-guidelines-why-your-index-exists-but-is-never-used-3fn8</link>
      <guid>https://dev.to/shubham_ravani/mongodb-indexing-guidelines-why-your-index-exists-but-is-never-used-3fn8</guid>
      <description>&lt;p&gt;MongoDB indexing issues rarely come from missing indexes.&lt;br&gt;&lt;br&gt;
They come from &lt;strong&gt;incorrect query and aggregation shape&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This document captures &lt;strong&gt;hard rules learned from real production systems&lt;/strong&gt;, where&lt;br&gt;
indexes existed but were never used, queries were slow, and &lt;code&gt;COLLSCAN&lt;/code&gt; appeared&lt;br&gt;
despite correct-looking indexes.&lt;/p&gt;

&lt;p&gt;(Collection names used below are illustrative but represent real production patterns.)&lt;/p&gt;


&lt;h2&gt;
  
  
  Core Principles
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Every index must map to a real query&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every index must have a documented reason&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Indexes are validated using &lt;code&gt;explain()&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unused indexes are technical debt&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aggregation shape determines index usability&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  How to Verify Index Usage (Read This First)
&lt;/h2&gt;

&lt;p&gt;Before creating or blaming an index, always verify usage.&lt;/p&gt;
&lt;h3&gt;
  
  
  Query Planner
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;explain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;queryPlanner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;([...])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;winningPlan.stage = IXSCAN&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Execution Stats (MANDATORY)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;explain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;executionStats&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;([...])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;totalDocsExamined&lt;/code&gt; is low&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;totalKeysExamined&lt;/code&gt; is reasonable&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;COLLSCAN&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;queryPlanner&lt;/code&gt; shows possible plans.&lt;br&gt;&lt;br&gt;
&lt;code&gt;executionStats&lt;/code&gt; shows what actually executed.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  Index Usage Counter
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aggregate&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt; &lt;span class="na"&gt;$indexStats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Interpretation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ops &amp;gt; 0&lt;/code&gt; → active index&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ops = 0&lt;/code&gt; → candidate for removal&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Index Design Rules
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Rule 1: Entry Point Matters
&lt;/h3&gt;

&lt;p&gt;MongoDB executes aggregation pipelines left to right.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Indexes apply &lt;strong&gt;only to the collection where the pipeline starts&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$lookup&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; reorder execution like SQL joins.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Example (Form ↔ FormStep)
&lt;/h3&gt;

&lt;p&gt;✅ Good (filter &lt;code&gt;FormStep&lt;/code&gt; first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;FormStep&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$match&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$lookup&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ Bad (filter after join):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$lookup&lt;/span&gt; &lt;span class="nx"&gt;FormStep&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$match&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Example (Payment ↔ WalletPayment)
&lt;/h3&gt;

&lt;p&gt;✅ Good (filter &lt;code&gt;WalletPayment&lt;/code&gt; first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;WalletPayment&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$match&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$lookup&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Payment&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$lookup&lt;/span&gt; &lt;span class="nx"&gt;WalletPayment&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$match&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you start on the wrong collection, &lt;strong&gt;no index can save you.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Rule 2: Unique Equality Ends Index Traversal
&lt;/h3&gt;

&lt;p&gt;If a query includes equality on a &lt;strong&gt;unique field&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;paymentId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB uses &lt;strong&gt;only that unique index&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;No compound index fields after it will be used&lt;/li&gt;
&lt;li&gt;This is &lt;strong&gt;expected behavior&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example (unique &lt;code&gt;paymentId&lt;/code&gt;)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;WalletPayment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;paymentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;paymentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SUCCESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$gte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;$lte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if this index exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@@index([status, date])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MongoDB will still use &lt;strong&gt;only&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WalletPayment_paymentId_key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;paymentId&lt;/code&gt; is unique, the query is resolved after the equality match, and the remaining predicates are evaluated in memory.&lt;/p&gt;




&lt;h3&gt;
  
  
  Rule 3: &lt;code&gt;$expr&lt;/code&gt; Prevents Index Optimization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$expr&lt;/code&gt; may still touch an index&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BUT it prevents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;range bounds&lt;/li&gt;
&lt;li&gt;compound index usage&lt;/li&gt;
&lt;li&gt;efficient scans&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;❌ Avoid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$expr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;$gte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$createdAt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;$gte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use $expr, assume &lt;strong&gt;reduced index effectiveness.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule 4: &lt;code&gt;$lookup&lt;/code&gt; Index Rules
&lt;/h2&gt;

&lt;p&gt;Indexes on the &lt;strong&gt;foreign collection&lt;/strong&gt; are used only if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$match&lt;/code&gt; is inside &lt;code&gt;$lookup.pipeline&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$match&lt;/code&gt; is the &lt;strong&gt;first stage&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;$expr&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Predicates are &lt;strong&gt;sargable&lt;/strong&gt; (direct field comparisons)&lt;/li&gt;
&lt;li&gt;No unique equality dominates the lookup&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;$lookup&lt;/code&gt; with &lt;code&gt;let&lt;/code&gt; variables internally uses &lt;code&gt;$expr&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Index usage is still possible only when equality predicates remain sargable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Example (Form → FormStep)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$lookup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FormStep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;formId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;$match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;formId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$$formId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;steps&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Index used on &lt;code&gt;FormStep&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@@index([formId, status])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Example (Payment → WalletPayment)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$lookup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WalletPayment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;paymentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;$match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;paymentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$$paymentId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SUCCESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;$gte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;$lte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;endDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;walletPayment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;paymentId&lt;/code&gt; is &lt;strong&gt;unique&lt;/strong&gt;, MongoDB will still resolve the lookup using only the unique &lt;code&gt;paymentId&lt;/code&gt; index&lt;/li&gt;
&lt;li&gt;Indexes on &lt;code&gt;status&lt;/code&gt; or &lt;code&gt;date&lt;/code&gt; will &lt;strong&gt;not&lt;/strong&gt; be traversed&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Rule 5: &lt;code&gt;$match&lt;/code&gt; After &lt;code&gt;$lookup&lt;/code&gt; Is In-Memory
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$lookup&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$unwind&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$match&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ Indexes on the joined collection will NOT be used.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bad example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$lookup&lt;/span&gt; &lt;span class="nx"&gt;FormStep&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$match&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;steps.status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Good example
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;FormStep&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$match&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PENDING&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;$lookup&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always filter &lt;strong&gt;before&lt;/strong&gt; or &lt;strong&gt;inside&lt;/strong&gt; &lt;code&gt;$lookup&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Aggregation-Specific Guidelines
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Date Filtering
&lt;/h3&gt;

&lt;p&gt;Always filter dates using &lt;strong&gt;direct field predicates&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;$gte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;$lte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never use &lt;code&gt;$expr&lt;/code&gt; for date ranges.&lt;/p&gt;




&lt;h3&gt;
  
  
  Sorting
&lt;/h3&gt;

&lt;p&gt;If you sort:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;$sort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;createdAt&lt;/code&gt; must appear &lt;strong&gt;last&lt;/strong&gt; in the index.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;code&gt;$facet&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Each facet runs its own pipeline.&lt;br&gt;
Indexes must support &lt;strong&gt;each facet independently&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Index Removal Policy
&lt;/h2&gt;

&lt;p&gt;An index &lt;strong&gt;must be reviewed for removal&lt;/strong&gt; if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ops = 0&lt;/code&gt; for 14 days in production&lt;/li&gt;
&lt;li&gt;No query references it in the registry&lt;/li&gt;
&lt;li&gt;It was created speculatively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Removing unused indexes is &lt;strong&gt;safe and healthy&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Golden Rules (Memorize These)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;One index = one query pattern&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$match&lt;/code&gt; early or inside &lt;code&gt;$lookup&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Unique equality dominates everything&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$expr&lt;/code&gt; kills optimization&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$lookup&lt;/code&gt; is not SQL JOIN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ops = 0&lt;/code&gt; means debt&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Note
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Indexes do not make queries fast.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Correct query shape makes indexes usable.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>mongodb</category>
      <category>backend</category>
      <category>performance</category>
      <category>database</category>
    </item>
  </channel>
</rss>
