<?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: VisuaLeaf</title>
    <description>The latest articles on DEV Community by VisuaLeaf (@visualeaf).</description>
    <link>https://dev.to/visualeaf</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%2F3818324%2F6cb54fe1-a36c-4f1a-a7b5-fa360f5daf8a.png</url>
      <title>DEV Community: VisuaLeaf</title>
      <link>https://dev.to/visualeaf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/visualeaf"/>
    <language>en</language>
    <item>
      <title>Compare MongoDB Collections Between Local and Atlas</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Tue, 09 Jun 2026 08:48:13 +0000</pubDate>
      <link>https://dev.to/visualeaf/compare-mongodb-collections-between-local-and-atlas-5c7f</link>
      <guid>https://dev.to/visualeaf/compare-mongodb-collections-between-local-and-atlas-5c7f</guid>
      <description>&lt;p&gt;When you work with MongoDB, your data does not always stay in one place.&lt;/p&gt;

&lt;p&gt;You may have one database running locally, another one used for staging, and another one hosted in MongoDB Atlas.&lt;/p&gt;

&lt;p&gt;At the beginning, they may look the same.&lt;/p&gt;

&lt;p&gt;But after a few tests, imports, updates, or small manual changes, they can slowly become different.&lt;/p&gt;

&lt;p&gt;And this is where the annoying question appears:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Is my local collection still the same as the one in Atlas?&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, Collection Compare helps you answer that without opening both collections side by side and checking documents one by one.&lt;/p&gt;

&lt;p&gt;For this example, I compared a local &lt;code&gt;payments&lt;/code&gt; collection with the same collection from a production cluster in MongoDB Atlas. In VisuaLeaf, I selected the local collection as the source and the Atlas collection as the target.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcp3kpb34vc0aknuwn511.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcp3kpb34vc0aknuwn511.png" alt="VisuaLeaf compares a local MongoDB payments collection with a MongoDB Atlas payments collection." width="800" height="837"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the Atlas &lt;code&gt;payments&lt;/code&gt; collection I used as the target for this comparison.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kgss0sf6r1sgy88z12o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kgss0sf6r1sgy88z12o.png" alt="VisuaLeaf showing the MongoDB Atlas payments collection used as the target collection." width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is Useful
&lt;/h2&gt;

&lt;p&gt;This kind of comparison is useful because MongoDB projects usually have more than one environment.&lt;/p&gt;

&lt;p&gt;You may test payments locally.&lt;br&gt;&lt;br&gt;
Someone else may update data in Atlas.&lt;br&gt;&lt;br&gt;
A staging database may have older documents.&lt;br&gt;&lt;br&gt;
A production collection may contain records that do not exist locally.&lt;/p&gt;

&lt;p&gt;At some point, you need to know what is different.&lt;/p&gt;

&lt;p&gt;Not in theory.&lt;br&gt;&lt;br&gt;
Not by guessing.&lt;br&gt;&lt;br&gt;
You need to actually see it.&lt;/p&gt;

&lt;p&gt;In my example, the source collection is from local development, and the target collection is from MongoDB Atlas.&lt;/p&gt;

&lt;p&gt;VisuaLeaf compares both collections and shows the result in a clear summary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxdi9djjvu6syfj64c94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxdi9djjvu6syfj64c94.png" alt="VisuaLeaf comparison results showing document differences between local and Atlas payments collections." width="800" height="825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this comparison, the local &lt;code&gt;payments&lt;/code&gt; collection had 312 documents, while the Atlas collection had 300 documents.&lt;/p&gt;

&lt;p&gt;Most of them were identical, but not all.&lt;/p&gt;

&lt;p&gt;The result showed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;296 identical documents  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1 modified document  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;3 documents missing in source  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;15 documents missing in target  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is already useful because you do not have to manually count or search for these differences.&lt;/p&gt;

&lt;p&gt;You can immediately see where the collections do not match.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use Filters When You Do Not Want to Compare Everything
&lt;/h2&gt;

&lt;p&gt;Sometimes you do not need to compare the full collection.&lt;/p&gt;

&lt;p&gt;For example, in a &lt;code&gt;payments&lt;/code&gt; collection, I may not want to compare every failed, pending, or small test payment.&lt;/p&gt;

&lt;p&gt;In this case, I can add a simple visual filter and compare only:&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;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8oacn0q4bt9jzyybwss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8oacn0q4bt9jzyybwss.png" alt="VisuaLeaf visual filter for comparing completed MongoDB payments with amount greater than 1000." width="800" height="841"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This keeps the comparison more focused.&lt;/p&gt;

&lt;p&gt;Instead of checking the entire collection, VisuaLeaf compares only the payments that match these conditions in both the local database and MongoDB Atlas.&lt;/p&gt;

&lt;p&gt;That makes the result easier to review, especially when the collection contains old data, test documents, or payments that are not relevant for the current check.&lt;/p&gt;

&lt;h2&gt;
  
  
  See What Exists Only in Atlas
&lt;/h2&gt;

&lt;p&gt;One of the tabs shows documents that are missing in the source.&lt;/p&gt;

&lt;p&gt;In this example, those are documents that exist in Atlas, but not in the local collection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34m0p9x891j82gv9ob4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34m0p9x891j82gv9ob4h.png" alt="VisuaLeaf showing payments that exist in MongoDB Atlas but are missing from the local MongoDB collection." width="800" height="668"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can happen when production has new payments that were never copied locally.&lt;/p&gt;

&lt;p&gt;It can also happen when someone inserted data directly in Atlas, or when the local database is simply behind.&lt;/p&gt;

&lt;p&gt;The useful part is that VisuaLeaf does not only say “something is missing.”&lt;/p&gt;

&lt;p&gt;It shows the document IDs and the fields, so you can inspect what is actually different.&lt;/p&gt;

&lt;h2&gt;
  
  
  See What Exists Only Locally
&lt;/h2&gt;

&lt;p&gt;The opposite case is also common.&lt;/p&gt;

&lt;p&gt;You may have documents locally that do not exist in Atlas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q34ujijbasarquvvgxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q34ujijbasarquvvgxl.png" alt="VisuaLeaf showing local MongoDB payments that are missing from the MongoDB Atlas collection." width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my example, VisuaLeaf found 15 documents missing in the target.&lt;/p&gt;

&lt;p&gt;That means these documents exist in the local &lt;code&gt;payments&lt;/code&gt; collection, but not in the Atlas collection.&lt;/p&gt;

&lt;p&gt;This is a very common situation when you test locally.&lt;/p&gt;

&lt;p&gt;You insert some data, run a few queries, maybe prepare a demo, and later you forget which documents were only local.&lt;/p&gt;

&lt;p&gt;With Collection Compare, you can see those differences directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check Modified Documents
&lt;/h2&gt;

&lt;p&gt;Missing documents are easy to understand.&lt;/p&gt;

&lt;p&gt;But modified documents are often more important.&lt;/p&gt;

&lt;p&gt;A document may exist in both collections, but one field may have a different value.&lt;/p&gt;

&lt;p&gt;In my example, one payment document was modified.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0olw8x4fa9lrtgx5mm8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0olw8x4fa9lrtgx5mm8v.png" alt="VisuaLeaf showing a modified MongoDB payment where the amount is 1000 locally and 3000 in MongoDB Atlas." width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The document exists on both sides, but the &lt;code&gt;amount&lt;/code&gt; field is different.&lt;/p&gt;

&lt;p&gt;In the source, the amount is &lt;code&gt;1000&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
In the target, the amount is &lt;code&gt;3000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This kind of difference can easily create confusion.&lt;/p&gt;

&lt;p&gt;Maybe a chart shows a different revenue total.&lt;br&gt;&lt;br&gt;
Maybe an aggregation result looks wrong.&lt;br&gt;&lt;br&gt;
Maybe a report does not match what you tested locally.&lt;/p&gt;

&lt;p&gt;The query or aggregation may not be the problem.&lt;/p&gt;

&lt;p&gt;The data may simply be different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate a Sync Plan Before Changing Anything
&lt;/h2&gt;

&lt;p&gt;After reviewing the differences, VisuaLeaf can also generate a sync plan.&lt;/p&gt;

&lt;p&gt;This is important because you should not sync blindly, especially when you compare local data with MongoDB Atlas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqbnk9d31jrw6y5k539h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqbnk9d31jrw6y5k539h.png" alt="VisuaLeaf sync plan preview showing one MongoDB payment update before execution." width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the sync plan, VisuaLeaf also asks for confirmation before applying the change.&lt;/p&gt;

&lt;p&gt;Here, I can still choose how the modified document should be synced. For example, I can replace the full document or merge only the changed fields.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuz8vr3i1j427sgcs7ktu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuz8vr3i1j427sgcs7ktu.png" alt="modified document should be synced" width="610" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the sync is not applied immediately. I can review the change first, choose the strategy, and only then start the sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  Share the Comparison With Your Team
&lt;/h2&gt;

&lt;p&gt;Collection Compare is also useful when you work with other people.&lt;/p&gt;

&lt;p&gt;Maybe one person changed the local data.&lt;br&gt;&lt;br&gt;
Maybe another person updated Atlas.&lt;br&gt;&lt;br&gt;
Maybe someone wants to review the differences before anything is synced.&lt;/p&gt;

&lt;p&gt;Instead of explaining everything in a message, you can export the comparison and share it with the team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr89ofmbz1dil11d0ew39.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr89ofmbz1dil11d0ew39.png" alt="VisuaLeaf Export Comparison dialog with password protection for sharing MongoDB comparison results." width="554" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VisuaLeaf also lets you protect the exported file with a password, which is useful when the comparison contains real data.&lt;/p&gt;

&lt;p&gt;This makes the review easier because everyone can look at the same result.&lt;/p&gt;

&lt;p&gt;They can see what is missing, what changed, and what should be checked before moving forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Collection Compare is useful when two MongoDB collections look similar, but you are not sure if they really match.&lt;/p&gt;

&lt;p&gt;In this example, the local &lt;code&gt;payments&lt;/code&gt; collection and the Atlas &lt;code&gt;payments&lt;/code&gt; collection were not identical. Some payments existed only locally, some existed only in Atlas, and one payment had a different amount.&lt;/p&gt;

&lt;p&gt;With VisuaLeaf, those differences are easier to see before syncing, debugging, or sharing the result with a teammate.&lt;/p&gt;

&lt;p&gt;That is the main point of the feature: you do not have to guess what changed between two collections. You can compare them, review the differences, and decide what to do next.&lt;/p&gt;

&lt;p&gt;To try this workflow, you can download VisuaLeaf here: &lt;a href="https://visualeaf.com/download/" rel="noopener noreferrer"&gt;https://visualeaf.com/download/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also explore the Collection Compare feature here: &lt;a href="https://visualeaf.com/features/collection-compare/" rel="noopener noreferrer"&gt;https://visualeaf.com/features/collection-compare/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>database</category>
      <category>developers</category>
      <category>nosql</category>
    </item>
    <item>
      <title>NoSQLBooster Alternative - Visual MongoDB Shell Workflow</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Thu, 04 Jun 2026 18:00:00 +0000</pubDate>
      <link>https://dev.to/visualeaf/nosqlbooster-alternative-visual-mongodb-shell-workflow-3po1</link>
      <guid>https://dev.to/visualeaf/nosqlbooster-alternative-visual-mongodb-shell-workflow-3po1</guid>
      <description>&lt;p&gt;If you use MongoDB and want a GUI tool to help you work faster, &lt;a href="https://nosqlbooster.com/" rel="noopener noreferrer"&gt;NoSQLBooster&lt;/a&gt; is often one of the tools you’ll hear about.&lt;/p&gt;

&lt;p&gt;It has a strong reputation for a reason. It gives developers a shell-focused way to work with MongoDB and can handle queries, scripts, aggregations, SQL-style queries, and other database tasks from one place.&lt;/p&gt;

&lt;p&gt;But maybe you want something different.&lt;/p&gt;

&lt;p&gt;You still want the MongoDB Shell, but not as a separate place where you write commands and then struggle to understand the result.&lt;/p&gt;

&lt;p&gt;You want to write a command, run it, inspect the data clearly, save useful scripts, and move into visual query building or aggregation work when it makes sense.&lt;/p&gt;

&lt;p&gt;That’s where &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt; takes a different approach.&lt;/p&gt;

&lt;p&gt;It keeps the &lt;a href="https://visualeaf.com/" rel="noopener noreferrer"&gt;MongoDB Shell&lt;/a&gt; within the workspace while providing visual output, autocomplete, saved scripts, query tools, and aggregation builders.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgx0frlf061d26ej28ew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgx0frlf061d26ej28ew.png" alt="VisuaLeaf MongoDB Shell showing a payment query on the left and results in a visual pane on the right." width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why VisuaLeaf Can Be a NoSQLBooster Alternative
&lt;/h2&gt;

&lt;p&gt;NoSQLBooster is a good choice if you want a classic MongoDB IDE built strongly around shell usage, scripting, SQL-style querying, monitoring, and debugging.&lt;/p&gt;

&lt;p&gt;VisuaLeaf is better suited for users who want the shell but also want the workflow around it to feel easier to follow.&lt;/p&gt;

&lt;p&gt;The difference is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;use the shell when writing commands is faster  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;use visual output when the result is harder to read  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;use saved scripts when the work repeats  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;use the visual query builder when filters become annoying to write manually  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;use the aggregation builder when pipelines become too long to understand at once&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the point is not only “VisuaLeaf has a shell.”&lt;/p&gt;

&lt;p&gt;The point is that the shell is connected to the rest of the MongoDB workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run a Shell Query and Read the Result Immediately
&lt;/h2&gt;

&lt;p&gt;The real difference is visible after you run a command.&lt;/p&gt;

&lt;p&gt;For example, you can write a shell query like this:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&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="mi"&gt;1000&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;In a classic shell workflow, you usually continue by reading the output as raw documents.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, the result appears directly below the command, in a visual table view.&lt;/p&gt;

&lt;p&gt;So instead of scanning raw JSON, you can immediately see the matching payments, compare amounts, check the currency, and open nested fields like &lt;code&gt;billing&lt;/code&gt; or &lt;code&gt;items&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This makes the shell more practical for everyday work.&lt;/p&gt;

&lt;p&gt;You still write the command yourself, but the result is easier to read and continue working with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2641h1dwiyl8znvv0tjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2641h1dwiyl8znvv0tjr.png" alt="VisuaLeaf MongoDB Shell showing a payments query with visual table results" width="800" height="648"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can learn more here: &lt;a href="https://visualeaf.com/blog/mongodb-shell-visual-output/" rel="noopener noreferrer"&gt;https://visualeaf.com/blog/mongodb-shell-visual-output/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Write Commands Faster With Autocomplete
&lt;/h2&gt;

&lt;p&gt;Autocomplete is useful because it helps you move faster while still writing commands yourself.&lt;/p&gt;

&lt;p&gt;For example, when you start typing:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can continue with methods like:&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="nf"&gt;find&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="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;updateOne&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;deleteOne&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps when you switch between collections, methods, operators, and repeated commands.&lt;/p&gt;

&lt;p&gt;You still control the query, but the tool helps you avoid small mistakes and write faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dnn92z2xiim6t2suqyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6dnn92z2xiim6t2suqyu.png" alt="MongoDB Shell autocomplete in VisuaLeaf showing method suggestions for the payments collection" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Read Commands More Clearly with Syntax Highlighting
&lt;/h2&gt;

&lt;p&gt;When a query has only one condition, it is easy to read.&lt;/p&gt;

&lt;p&gt;But once you add dates, operators, and selected fields, the command becomes harder to scan:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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="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="s2"&gt;paid&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="s2"&gt;refunded&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;paidAt&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="nc"&gt;ISODate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-01-01T00:00:00Z&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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;paidAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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;This is where a clearer editor experience helps.&lt;/p&gt;

&lt;p&gt;Fields, values, operators, dates, and brackets are easier to separate, so you can understand the command faster and change it without losing the structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx36uzenxib3a08yg4o0b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx36uzenxib3a08yg4o0b.png" alt="VisuaLeaf MongoDB Shell showing a highlighted query with status filter, date condition, and selected payment fields" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Save Useful Scripts and Reuse Previous Queries
&lt;/h2&gt;

&lt;p&gt;A lot of MongoDB work repeats itself.&lt;/p&gt;

&lt;p&gt;Maybe you often check failed payments:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&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;Maybe you can check payments from a specific period:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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;createdAt&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="nc"&gt;ISODate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-01-01T00:00:00Z&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or maybe you test the same query with small changes.&lt;/p&gt;

&lt;p&gt;These commands should not have to be rewritten every time.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can save useful scripts in the Script Library and reopen them later when you need them again.&lt;/p&gt;

&lt;p&gt;You can also use Query History to return to commands you already ran, rerun them, and adjust them without starting from zero.&lt;/p&gt;

&lt;p&gt;That makes the shell much more practical for everyday work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3ix9bsvulvp6n8vh4gt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3ix9bsvulvp6n8vh4gt.png" alt="VisuaLeaf Query History showing previously executed MongoDB shell commands" width="800" height="791"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Queries Without Writing Code
&lt;/h2&gt;

&lt;p&gt;Not every query needs to be written manually.&lt;/p&gt;

&lt;p&gt;Sometimes the shell is faster.&lt;/p&gt;

&lt;p&gt;Other times, especially with multiple filters or AND/OR logic, visual query building is easier.&lt;/p&gt;

&lt;p&gt;VisuaLeaf lets you &lt;a href="https://visualeaf.com/features/visual-query-builder/" rel="noopener noreferrer"&gt;build queries visually&lt;/a&gt; and still see the generated query behind it.&lt;/p&gt;

&lt;p&gt;So you can write directly in the shell when that is faster, or build visually when the query becomes harder to follow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxr9kj1ez023lkh776pd6.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxr9kj1ez023lkh776pd6.webp" alt="VisuaLeaf visual query builder for MongoDB with filters, conditions, and live query preview" width="799" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build MongoDB queries faster with VisuaLeaf’s visual query builder&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Aggregation Pipelines Step by Step
&lt;/h2&gt;

&lt;p&gt;Aggregations are powerful, but they can quickly become hard to read.&lt;/p&gt;

&lt;p&gt;A short pipeline is fine:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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="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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&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="na"&gt;$group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$method&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$amount&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$sort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;totalAmount&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;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;But once you add more stages, filters, groups, and transformations, the pipeline becomes harder to follow.&lt;/p&gt;

&lt;p&gt;That is where a visual aggregation builder helps.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can &lt;a href="https://visualeaf.com/features/aggregation-pipeline/" rel="noopener noreferrer"&gt;build the pipeline step by step&lt;/a&gt; and see the output for each stage. This makes it easier to understand what changed and where.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy6rfp8y04lendxb7rdih.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy6rfp8y04lendxb7rdih.webp" alt="VisuaLeaf aggregation pipeline builder showing stages, filters, and real-time results preview" width="799" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build MongoDB aggregation pipelines step by step with live preview&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For longer aggregations, a visual pipeline builder can make each stage easier to understand.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Less Switching Between Tools
&lt;/h2&gt;

&lt;p&gt;This is one of the biggest reasons VisuaLeaf feels different.&lt;/p&gt;

&lt;p&gt;You do not have to keep moving between a shell, a query builder, an aggregation editor, and another tool for visual results.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, these workflows stay closer together.&lt;/p&gt;

&lt;p&gt;You can use the MongoDB Shell, visual query builder, aggregation pipeline builder, and visual result views from one workspace.&lt;/p&gt;

&lt;p&gt;Use the shell when the shell is fastest.&lt;/p&gt;

&lt;p&gt;Use visual tools when the work becomes harder to follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  NoSQLBooster vs VisuaLeaf
&lt;/h2&gt;

&lt;p&gt;NoSQLBooster is a strong option for users who want a classic MongoDB IDE focused on shell scripting and developer-oriented workflows.&lt;/p&gt;

&lt;p&gt;VisuaLeaf is built with a different perspective.&lt;/p&gt;

&lt;p&gt;It keeps the shell available, but connects it with a more visual way of working with MongoDB.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;NoSQLBooster&lt;/th&gt;
&lt;th&gt;VisuaLeaf&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MongoDB shell&lt;/td&gt;
&lt;td&gt;Embedded mongosh engine&lt;/td&gt;
&lt;td&gt;Full shell compatibility with visual output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autocomplete&lt;/td&gt;
&lt;td&gt;True IntelliSense&lt;/td&gt;
&lt;td&gt;Context-aware autocomplete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Syntax highlighting&lt;/td&gt;
&lt;td&gt;Editor assistance for writing code&lt;/td&gt;
&lt;td&gt;Syntax highlighting in query and aggregation editors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script history&lt;/td&gt;
&lt;td&gt;More focused on shell-based work&lt;/td&gt;
&lt;td&gt;Script management and history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Saved scripts&lt;/td&gt;
&lt;td&gt;User-saved query scripts in “My Queries”&lt;/td&gt;
&lt;td&gt;Save scripts to a library and organize by project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visual query builder&lt;/td&gt;
&lt;td&gt;Not highlighted as the main workflow&lt;/td&gt;
&lt;td&gt;Visual query builder with real-time query preview&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregation pipeline builder&lt;/td&gt;
&lt;td&gt;Aggregation is supported&lt;/td&gt;
&lt;td&gt;Visual pipeline builder with stage preview and code mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visual result exploration&lt;/td&gt;
&lt;td&gt;Results tab and data viewer&lt;/td&gt;
&lt;td&gt;Tree, Table, BSON, and Explain views&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Charts and dashboards&lt;/td&gt;
&lt;td&gt;Not the main focus&lt;/td&gt;
&lt;td&gt;Query- and aggregation-driven chart tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Shell-heavy IDE workflow with SQL, monitoring, and debugging&lt;/td&gt;
&lt;td&gt;Visual MongoDB Shell workflow with nearby builders and views&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;NoSQLBooster has a strong reputation for a reason.&lt;/p&gt;

&lt;p&gt;It is a powerful MongoDB IDE, especially for users who enjoy shell-heavy workflows.&lt;/p&gt;

&lt;p&gt;But if you want a different way to work with MongoDB Shell, VisuaLeaf is worth considering.&lt;/p&gt;

&lt;p&gt;It keeps the shell available, but makes the workflow around it more visual.&lt;/p&gt;

&lt;p&gt;You can write commands, use autocomplete, inspect results, save scripts, build queries, create aggregations, and continue working with MongoDB from one place.&lt;/p&gt;

&lt;p&gt;If you want to try it yourself, explore the MongoDB Shell in VisuaLeaf and see how it fits into a more visual MongoDB workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokjgfvfyltfrcfb3wjfa.png" alt="CTA Image" width="799" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;Download for Free&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>database</category>
      <category>developers</category>
    </item>
    <item>
      <title>3 Common MongoDB Mistakes Developers Make (And How to Fix Them)</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Thu, 04 Jun 2026 17:59:00 +0000</pubDate>
      <link>https://dev.to/visualeaf/3-common-mongodb-mistakes-developers-make-and-how-to-fix-them-23fh</link>
      <guid>https://dev.to/visualeaf/3-common-mongodb-mistakes-developers-make-and-how-to-fix-them-23fh</guid>
      <description>&lt;p&gt;&lt;em&gt;A guide to thinking in documents, not tables.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I've seen a lot of MongoDB projects over the years. Some were successes. Some were disasters that ended in painful migrations. The difference between them had nothing to do with the scale of data, the complexity of the domain, or whether MongoDB was "the right choice."&lt;/p&gt;

&lt;p&gt;The issue: &lt;strong&gt;the different mentality between thinking in SQL and thinking in MongoDB.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  This Isn't About Which Database Is "Better"
&lt;/h2&gt;

&lt;p&gt;This article isn't here to tell you MongoDB is universally superior to SQL. That debate is meaningless. The real question is: &lt;strong&gt;which one fits your situation?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think of your data as cargo you need to transport. SQL is like a sports car—you make fast, precise trips back and forth to fetch exactly what you need from different locations. MongoDB is like a moving truck—you pack everything from one place and ship it all to the destination in a single trip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQL shines when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your data has complex, independent relationships&lt;/li&gt;
&lt;li&gt;Multiple teams need to own and modify different entities separately&lt;/li&gt;
&lt;li&gt;You need strict referential integrity enforced at the database level&lt;/li&gt;
&lt;li&gt;Your access patterns vary wildly and unpredictably&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;MongoDB shines when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Related data is accessed together&lt;/li&gt;
&lt;li&gt;Your application thinks in documents/objects&lt;/li&gt;
&lt;li&gt;Read performance matters more than write complexity&lt;/li&gt;
&lt;li&gt;Your schema needs to evolve quickly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mistake isn't choosing MongoDB. The mistake is choosing MongoDB and then using it like SQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mistake #1: Designing MongoDB Like It's SQL
&lt;/h2&gt;

&lt;p&gt;I've seen projects where developers designed their MongoDB schema exactly how they would design SQL—creating separate collections for &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_items&lt;/code&gt;, &lt;code&gt;products&lt;/code&gt;, &lt;code&gt;categories&lt;/code&gt;. Perfectly normalized. And perfectly slow.&lt;/p&gt;

&lt;p&gt;They changed their query syntax from SQL to MongoDB but kept thinking in rows and foreign keys. The database changed, but they didn't utilize MongoDB's main advantages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Golden Rule:&lt;/strong&gt; &lt;a href="https://www.mongodb.com/docs/manual/data-modeling/" rel="noopener noreferrer"&gt;Data that is accessed together should be stored together.&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Mistake #2: The "Reference Everything" Reflex
&lt;/h2&gt;

&lt;p&gt;SQL trained us that duplication is evil. Normalize. Reference. Never store the same data twice.&lt;/p&gt;

&lt;p&gt;This instinct creates MongoDB code like:&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="c1"&gt;// Order document&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customer456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;// Just a reference&lt;/span&gt;
  &lt;span class="nx"&gt;productIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;  &lt;span class="c1"&gt;// More references&lt;/span&gt;
  &lt;span class="nx"&gt;shippingAddressId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addr789&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Yet another reference&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To display this order, you need four queries. Or an aggregation with three &lt;code&gt;$lookup&lt;/code&gt; stages. Either way, you're doing at runtime what could have been done at write time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this happens:&lt;/strong&gt; MongoDB does not automatically optimize cross collection joins the way relational databases optimize joins. Each &lt;code&gt;$lookup&lt;/code&gt; is executed as part of the aggregation pipeline and can add additional processing per stage. This cost is paid on every query that uses &lt;code&gt;$lookup&lt;/code&gt;, and in many applications reads significantly outnumber writes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Think Instead: What's the Read/Write Ratio?
&lt;/h3&gt;

&lt;p&gt;In MongoDB, duplicating data is often a valid performance strategy rather than a mistake.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Duplication eliminates the need for lookups (joins) during read operations, significantly increasing speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trade-off:&lt;/strong&gt; You gain faster reads at the cost of more complex writes, as you must update the data in multiple places. This is most effective when data is read frequently but updated rarely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you write an order once and read it a hundred times, optimize for reads:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customer456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice Smith&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alice@test.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;items&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;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blue Widget&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;29.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Red Gadget&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;49.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;shippingAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;street&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123 Main St&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Seattle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;98101&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;109.97&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One query. Zero lookups. Done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Know the Limits of Embedding
&lt;/h3&gt;

&lt;p&gt;A word of caution: MongoDB documents have a &lt;strong&gt;16MB size limit&lt;/strong&gt;. This means you can't embed unbounded data—don't try to store millions of log entries inside a single user document, or embed an unlimited comment history in a blog post.&lt;/p&gt;

&lt;p&gt;The rule of thumb: embed data that's bounded and accessed together. If an array could grow indefinitely, consider referencing instead, or use the &lt;a href="https://www.mongodb.com/blog/post/building-with-patterns-the-bucket-pattern" rel="noopener noreferrer"&gt;bucket pattern&lt;/a&gt; to split large datasets into manageable chunks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mistake #3: Putting an ORM Between You and the Database
&lt;/h2&gt;

&lt;p&gt;A developer joins a MongoDB project. They google "MongoDB Node.js" and find Mongoose. They install it. They define schemas. They use &lt;code&gt;.populate()&lt;/code&gt;. At least that's how I was taught, and I'm sure countless other developers learned the same way.&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="c1"&gt;// Mongoose "makes MongoDB easy"&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;populate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;customer&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="nf"&gt;populate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items.product&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="nf"&gt;populate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shippingAddress&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;That single line of code executes 4+ database queries. The developer thinks they wrote one query. The database sees four. When there are 50 items, it's 52 queries—the classic N+1 problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Case For and Against ORMs
&lt;/h3&gt;

&lt;p&gt;To be fair, Mongoose has legitimate use cases. It's great for rapid prototyping, provides solid TypeScript support, and its middleware hooks can simplify authentication and validation logic. For small projects or teams new to MongoDB, the guardrails can be helpful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But here's the problem:&lt;/strong&gt; Mongoose teaches SQL patterns with MongoDB syntax. It wraps documents in heavy objects. It hides what's actually happening. And &lt;code&gt;.populate()&lt;/code&gt; makes it too easy to accidentally create performance nightmares without realizing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Think Instead: Understand Your Queries
&lt;/h3&gt;

&lt;p&gt;Whether you use an ORM or not, you need to understand what your queries actually do. MongoDB has native schema validation that's often stricter than what most Mongoose projects implement:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orders&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;validator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;$jsonSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;bsonType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;required&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;customerId&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;items&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;total&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;status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;bsonType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decimal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;enum&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;pending&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;processing&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;shipped&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;delivered&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="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;The database enforces this. No library required.&lt;/p&gt;

&lt;p&gt;If you do use Mongoose, use it consciously. Run &lt;code&gt;explain()&lt;/code&gt; on your queries. Know when &lt;code&gt;.populate()&lt;/code&gt; is triggering multiple round trips.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;MongoDB doesn't fail. People fail to adapt to MongoDB.&lt;/p&gt;

&lt;p&gt;Every disaster story I've seen follows the same pattern: developers treat MongoDB like SQL with different syntax. They normalize everything. They reference instead of embed.&lt;/p&gt;

&lt;p&gt;The fix is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Embed data that's accessed together.&lt;/strong&gt; Stop making the database reassemble documents that should never have been split apart.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept strategic duplication.&lt;/strong&gt; Reads vastly outnumber writes in most applications. Optimize accordingly—but respect the 16MB document limit.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand your queries.&lt;/strong&gt; Whether you use an ORM or native drivers, know what your queries actually do.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And remember: the question was never "SQL vs MongoDB." The question is "what does my data look like, and how do I access it?"&lt;/p&gt;

&lt;p&gt;If your data lives in separate tables and requires complex joins across independent entities, SQL's relational model is built for that. If your data belongs together and is always accessed as a single unit, MongoDB's document model removes unnecessary work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design your database in the way that complements your data.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;Visualeaf&lt;/a&gt; is a modern MongoDB GUI designed for developers who want to understand their data. Visualize document structures, build aggregation pipelines, and debug queries—all without leaving your workflow.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>database</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Learn how MongoDB schema validation works with JSON Schema, when to use validation rules, and how to create them visually in VisuaLeaf.</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Wed, 03 Jun 2026 08:41:57 +0000</pubDate>
      <link>https://dev.to/visualeaf/learn-how-mongodb-schema-validation-works-with-json-schema-when-to-use-validation-rules-and-how-2ki7</link>
      <guid>https://dev.to/visualeaf/learn-how-mongodb-schema-validation-works-with-json-schema-when-to-use-validation-rules-and-how-2ki7</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/roxana_haidiner/mongodb-schema-validation-how-json-schema-keeps-your-data-clean-4kc7" class="crayons-story__hidden-navigation-link"&gt;MongoDB Schema Validation: How JSON Schema Keeps Your Data Clean&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/roxana_haidiner" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2224346%2Ff71cca7a-b282-4793-a3ae-b04d89957d47.png" alt="roxana_haidiner profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/roxana_haidiner" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Roxana-Maria Haidiner
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Roxana-Maria Haidiner
                
              
              &lt;div id="story-author-preview-content-3809152" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/roxana_haidiner" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2224346%2Ff71cca7a-b282-4793-a3ae-b04d89957d47.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Roxana-Maria Haidiner&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/roxana_haidiner/mongodb-schema-validation-how-json-schema-keeps-your-data-clean-4kc7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 3&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/roxana_haidiner/mongodb-schema-validation-how-json-schema-keeps-your-data-clean-4kc7" id="article-link-3809152"&gt;
          MongoDB Schema Validation: How JSON Schema Keeps Your Data Clean
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mongodb"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mongodb&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nosql"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nosql&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/database"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;database&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/developers"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;developers&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/roxana_haidiner/mongodb-schema-validation-how-json-schema-keeps-your-data-clean-4kc7" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;4&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/roxana_haidiner/mongodb-schema-validation-how-json-schema-keeps-your-data-clean-4kc7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Advanced MongoDB Interview Questions for Senior Developers in 2026</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Tue, 02 Jun 2026 09:04:53 +0000</pubDate>
      <link>https://dev.to/visualeaf/advanced-mongodb-interview-questions-for-senior-developers-in-2026-2hep</link>
      <guid>https://dev.to/visualeaf/advanced-mongodb-interview-questions-for-senior-developers-in-2026-2hep</guid>
      <description>&lt;p&gt;A practical guide for senior engineers , or interviewers screening for them. The questions here go past syntax and into the parts of MongoDB that only show up at scale: WiredTiger's cache behavior, sharding decisions, replication trade-offs, multi-document transactions, and the production-debugging patterns that you only learn from being on call.&lt;/p&gt;

&lt;p&gt;If you can answer the fundamentals (BSON, indexing, basic aggregation) but want to handle senior-level questions, this is the layer above. The fundamentals article , &lt;em&gt;MongoDB Interview Questions for Beginners&lt;/em&gt; , covers the prerequisite material.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Storage Engine &amp;amp; Performance Internals
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q1. What's the storage engine? What changed with WiredTiger?
&lt;/h3&gt;

&lt;p&gt;WiredTiger has been the default since 3.2 and the only option since 4.2. The relevant properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Document-level locking&lt;/strong&gt; instead of collection-level (MMAPv1's bottleneck).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Snapshot-isolation MVCC&lt;/strong&gt;: readers see a consistent snapshot, writers don't block readers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compression&lt;/strong&gt;: Snappy by default for documents, zlib/zstd optional. Indexes use prefix compression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configurable cache&lt;/strong&gt; (&lt;code&gt;storage.wiredTiger.engineConfig.cacheSizeGB&lt;/code&gt;). The rule of thumb is 50% of RAM minus 1 GB, leaving the rest for the OS page cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Q2. How does the WiredTiger cache interact with the OS page cache?
&lt;/h3&gt;

&lt;p&gt;WiredTiger holds &lt;em&gt;uncompressed&lt;/em&gt; working-set data in its own LRU cache. The OS holds the &lt;em&gt;compressed&lt;/em&gt; on-disk blocks in the page cache. So a hot working set ends up cached twice in different forms , which is why memory sizing is non-trivial. Hit ratios live in &lt;code&gt;db.serverStatus().wiredTiger.cache&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The implication: tuning &lt;code&gt;cacheSizeGB&lt;/code&gt; is a balance, not a maximum. Too high and you starve the OS page cache, defeating the second-level caching. Too low and WiredTiger evicts hot pages it could have kept.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q3. Why is my query slow even with an index?
&lt;/h3&gt;

&lt;p&gt;A short checklist that resolves 90% of real-world cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Not actually using the index&lt;/strong&gt; , &lt;code&gt;explain()&lt;/code&gt; will say &lt;code&gt;COLLSCAN&lt;/code&gt;. Common causes: regex without anchor, negation operators (&lt;code&gt;$ne&lt;/code&gt;, &lt;code&gt;$nin&lt;/code&gt;), type mismatch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index isn't selective&lt;/strong&gt; , e.g., indexing &lt;code&gt;gender&lt;/code&gt; in a dataset that's 50/50. The optimizer might still prefer a COLLSCAN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sort spills to disk&lt;/strong&gt; , in-memory sort cap is 100 MB; past that, the query fails unless you set &lt;code&gt;allowDiskUse: true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working set exceeds RAM&lt;/strong&gt; , every query becomes I/O-bound. Look at &lt;code&gt;cache.bytes read into cache&lt;/code&gt; over time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Index doesn't cover the sort&lt;/strong&gt; , even with &lt;code&gt;IXSCAN&lt;/code&gt;, the explain shows &lt;code&gt;SORT_KEY_GENERATOR&lt;/code&gt; afterwards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compound index in wrong order&lt;/strong&gt; , ESR violation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$lookup&lt;/code&gt; joining without an index on the foreign collection&lt;/strong&gt; , the join becomes O(N×M).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Q4. What's &lt;code&gt;$hint&lt;/code&gt; and when do you reach for it?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;hint()&lt;/code&gt; forces the query planner to use a specific index. The query planner usually picks well, but it occasionally picks poorly under shifting data distributions (it caches winning plans for 1000 ops / 5 minutes by default; replans on cache invalidation). &lt;code&gt;hint()&lt;/code&gt; is a band-aid , useful for production-pinning a known good plan while you fix the underlying index design.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q5. What does &lt;code&gt;db.collection.stats()&lt;/code&gt; tell you, and what do you look at?
&lt;/h3&gt;

&lt;p&gt;The metrics that matter day-to-day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;size&lt;/code&gt; / &lt;code&gt;storageSize&lt;/code&gt; , uncompressed vs on-disk. The ratio is your effective compression.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;count&lt;/code&gt; , document count.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;avgObjSize&lt;/code&gt; , large &lt;code&gt;avgObjSize&lt;/code&gt; is often a smell (oversize embedded arrays).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nindexes&lt;/code&gt; and &lt;code&gt;totalIndexSize&lt;/code&gt; , index count and total index bytes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wiredTiger.cache.bytes currently in the cache&lt;/code&gt; , how much of this collection is hot.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Replication
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q6. Explain a replica set.
&lt;/h3&gt;

&lt;p&gt;A group of mongod processes maintaining the same data. One &lt;strong&gt;primary&lt;/strong&gt; accepts writes; the rest are &lt;strong&gt;secondaries&lt;/strong&gt; replicating asynchronously via the &lt;strong&gt;oplog&lt;/strong&gt; (a capped collection). If the primary fails, the secondaries hold an election (Raft-based since 3.2) and elect a new primary, usually within ~10,12 seconds.&lt;/p&gt;

&lt;p&gt;Roles you might add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arbiter&lt;/strong&gt;: votes in elections but holds no data. Use sparingly , it can prevent rollbacks but doesn't increase fault tolerance for data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hidden&lt;/strong&gt;: replicates but is invisible to clients. Used for backups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delayed&lt;/strong&gt;: replicates with a lag, used as a "human-error" recovery target.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Q7. Read preferences and write concerns , what do they actually mean?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write concern&lt;/strong&gt; (&lt;code&gt;w&lt;/code&gt;): how many nodes must acknowledge a write before it's "done."
, &lt;code&gt;w: 1&lt;/code&gt; , primary only (default).
, &lt;code&gt;w: 'majority'&lt;/code&gt; , durable across failover.
, &lt;code&gt;w: &amp;lt;number&amp;gt;&lt;/code&gt; , exact node count.
, Plus &lt;code&gt;j: true&lt;/code&gt; for journal flush, &lt;code&gt;wtimeout&lt;/code&gt; for upper bound.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read concern&lt;/strong&gt;: what level of isolation reads see.
, &lt;code&gt;local&lt;/code&gt; , most recent, may be rolled back.
, &lt;code&gt;majority&lt;/code&gt; , only data acknowledged by a majority.
, &lt;code&gt;linearizable&lt;/code&gt; / &lt;code&gt;snapshot&lt;/code&gt; , strict serializability and transactional snapshots respectively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read preference&lt;/strong&gt;: which member to read from.
, &lt;code&gt;primary&lt;/code&gt; (default), &lt;code&gt;primaryPreferred&lt;/code&gt;, &lt;code&gt;secondary&lt;/code&gt;, &lt;code&gt;secondaryPreferred&lt;/code&gt;, &lt;code&gt;nearest&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read from secondaries only if you can tolerate stale data , replication is async.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q8. What's a rollback?
&lt;/h3&gt;

&lt;p&gt;If a primary accepts writes that aren't replicated to a majority, then loses its primary status (network partition, crash), the new primary won't have those writes. When the old primary rejoins, the unreplicated writes are saved to a &lt;code&gt;rollback&lt;/code&gt; directory and &lt;em&gt;not&lt;/em&gt; applied. Using &lt;code&gt;w: 'majority'&lt;/code&gt; prevents rollback losses by definition.&lt;/p&gt;

&lt;p&gt;The interview signal: if a candidate proposes "always &lt;code&gt;w: 1&lt;/code&gt; for speed," ask them how they'd recover if the just-acknowledged write was lost to a rollback. The good answer admits that &lt;code&gt;w: 1&lt;/code&gt; trades durability for latency, and that the right choice depends on the data.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Sharding
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q9. When do you shard, and what's a shard key?
&lt;/h3&gt;

&lt;p&gt;Shard when (in order of importance):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The working set no longer fits in any reasonable single node's RAM.&lt;/li&gt;
&lt;li&gt;Write throughput exceeds what a single primary can handle.&lt;/li&gt;
&lt;li&gt;Storage exceeds practical single-node limits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A &lt;strong&gt;shard key&lt;/strong&gt; is one or more fields MongoDB uses to partition documents into chunks. Properties of a good shard key:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High cardinality&lt;/strong&gt; , many distinct values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Even distribution of writes&lt;/strong&gt; , avoid monotonic keys (&lt;code&gt;_id&lt;/code&gt;, timestamps) for hashed-style write distribution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aligned with common queries&lt;/strong&gt; , queries that include the shard key are &lt;em&gt;targeted&lt;/em&gt; (sent to one shard); queries without it are &lt;em&gt;scatter-gather&lt;/em&gt; (sent to all).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Q10. Hashed vs ranged sharding?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ranged&lt;/strong&gt;: chunks span contiguous shard-key ranges. Range queries on the shard key hit only the necessary chunks. Risk: hot spots if the key is monotonic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hashed&lt;/strong&gt;: MongoDB hashes the shard key before assigning chunks. Writes distribute evenly even with a monotonic key. Range queries become scatter-gather.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real systems often use &lt;strong&gt;compound shard keys&lt;/strong&gt; that combine an even-distribution prefix with a query-aligned suffix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q11. What's a &lt;code&gt;mongos&lt;/code&gt;? What's a &lt;code&gt;config server&lt;/code&gt;?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mongos&lt;/code&gt; is the routing process the client connects to. It knows the chunk → shard map, routes queries, and merges results.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;config server&lt;/strong&gt; replica set stores cluster metadata (shard map, chunk locations). It's not in the data path of queries; it's queried by &lt;code&gt;mongos&lt;/code&gt; and the shards themselves.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A senior follow-up: what happens when the config servers go down? The cluster keeps serving reads and writes from cached metadata, but chunk migrations and metadata changes stop until the config servers come back.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Transactions &amp;amp; Consistency
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q12. Does MongoDB support ACID transactions?
&lt;/h3&gt;

&lt;p&gt;Yes , multi-document transactions since 4.0 (replica sets) and 4.2 (sharded). They're real ACID with snapshot isolation. The catch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default 60-second transaction limit. Tune &lt;code&gt;transactionLifetimeLimitSeconds&lt;/code&gt; if needed.&lt;/li&gt;
&lt;li&gt;They cost more than single-doc operations because of the snapshot-tracking overhead.&lt;/li&gt;
&lt;li&gt;Best practice: structure your schema so most operations stay single-document (atomic by default), and reach for transactions only when you genuinely need multi-document atomicity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The senior take: transactions are an escape hatch. If a candidate proposes them as the default solution for multi-collection workflows, they're treating MongoDB like Postgres. The first question to ask is "can this be modeled as a single document?"&lt;/p&gt;

&lt;h3&gt;
  
  
  Q13. How does single-document atomicity work?
&lt;/h3&gt;

&lt;p&gt;Every write to a single document is atomic, even across embedded subdocuments and arrays. That's the most underused feature in MongoDB schema design , if you embed related data, you get transactional updates for free. &lt;code&gt;$set&lt;/code&gt;, &lt;code&gt;$inc&lt;/code&gt;, &lt;code&gt;$push&lt;/code&gt;, etc., on the same document in one update are atomic.&lt;/p&gt;

&lt;p&gt;The follow-up: when does this break? Cross-document operations. As soon as you need atomicity across two documents (or two collections), single-doc atomicity is no help and you're either reaching for a transaction or restructuring the schema to embed.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Aggregation Deep Dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q14. What is &lt;code&gt;$merge&lt;/code&gt; vs &lt;code&gt;$out&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Both write aggregation results to a collection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$out&lt;/code&gt; &lt;strong&gt;replaces&lt;/strong&gt; the target collection entirely.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$merge&lt;/code&gt; does an upsert-style merge: insert new, update existing (you control the matching field and conflict resolution).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$merge&lt;/code&gt; is what you use for materialized views and ETL pipelines that need to be re-runnable without dropping the target. &lt;code&gt;$out&lt;/code&gt; is fine for one-shot exports but dangerous in any pipeline that another process reads from , readers will see the collection vanish and reappear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q15. How does &lt;code&gt;$graphLookup&lt;/code&gt; work?
&lt;/h3&gt;

&lt;p&gt;Recursive graph traversal inside aggregation , find ancestors/descendants by following a chain of references. Useful for org charts, comment trees, manager chains. The relevant fields: &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;startWith&lt;/code&gt;, &lt;code&gt;connectFromField&lt;/code&gt;, &lt;code&gt;connectToField&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt;, plus optional &lt;code&gt;maxDepth&lt;/code&gt; and &lt;code&gt;depthField&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Caveats: it can be slow without a good index on the connected field, it loads results into memory (subject to the 100 MB limit unless &lt;code&gt;allowDiskUse: true&lt;/code&gt;), and it can't cross shards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q16. How do you model a hierarchy / tree?
&lt;/h3&gt;

&lt;p&gt;Five common patterns, pick based on access:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;What you store&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parent reference&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ parent: ObjectId }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Frequent inserts, infrequent traversal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Child references&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ children: [ObjectId] }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reading immediate children fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Array of ancestors&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ ancestors: [a, b, c] }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Subtree lookups by &lt;code&gt;$elemMatch&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Materialized path&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ path: ',a,b,c,' }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Path-prefix regex queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nested set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ left, right }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read-heavy, write-rare hierarchies&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first three are the only ones I'd reach for in production with MongoDB. Materialized paths still come up in legacy schemas; nested sets almost never make sense in a document database.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Production Tactics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q17. How would you implement soft-delete?
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;deletedAt: Date | null&lt;/code&gt; field on every document plus a partial index that excludes soft-deleted rows from your common queries:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;partialFilterExpression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;deletedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;Bonus: every read-side query adds &lt;code&gt;deletedAt: null&lt;/code&gt;. Or better, route reads through a view that wraps that filter so a future developer can't forget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q18. How do you migrate a schema without downtime?
&lt;/h3&gt;

&lt;p&gt;The standard pattern: &lt;strong&gt;read both shapes, write the new shape, backfill, retire the old shape.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy code that &lt;em&gt;reads&lt;/em&gt; both old and new field layouts.&lt;/li&gt;
&lt;li&gt;Deploy code that &lt;em&gt;writes&lt;/em&gt; the new layout going forward (still reading both).&lt;/li&gt;
&lt;li&gt;Backfill old docs to the new layout in chunks (use cursor-based pagination by &lt;code&gt;_id&lt;/code&gt; to avoid duplicate visits).&lt;/li&gt;
&lt;li&gt;Once all docs are migrated, deploy code that reads only the new layout.&lt;/li&gt;
&lt;li&gt;Drop the old field/index.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each step is independently deployable and rollback-safe. The interview signal: a candidate who proposes "stop the writers, run the migration, restart" hasn't shipped one of these.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q19. How do you investigate a slow query in production?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Turn on the profiler at a sample rate: &lt;code&gt;db.setProfilingLevel(1, { slowms: 100, sampleRate: 0.1 })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Read from &lt;code&gt;db.system.profile&lt;/code&gt;, sort by &lt;code&gt;millis&lt;/code&gt;, group by &lt;code&gt;command.filter&lt;/code&gt; shape.&lt;/li&gt;
&lt;li&gt;Pull the top offenders, run &lt;code&gt;explain('executionStats')&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Decide between: add/modify an index, rewrite the query, or change the schema.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sample rate matters , turning the profiler all the way on in production tanks throughput on busy collections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q20. How do you index a field that's sometimes a string and sometimes an integer?
&lt;/h3&gt;

&lt;p&gt;Two routes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coerce on write , pick one type and enforce it via &lt;code&gt;$jsonSchema&lt;/code&gt;. Best long-term answer.&lt;/li&gt;
&lt;li&gt;Live with it: MongoDB will index both, but &lt;code&gt;find({field: "123"})&lt;/code&gt; won't match &lt;code&gt;field: 123&lt;/code&gt; (no implicit coercion). So queries become harder, not easier. Avoid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interview signal: the candidate who answers "use &lt;code&gt;$expr&lt;/code&gt; with &lt;code&gt;$convert&lt;/code&gt;" understands the operator surface but is solving the symptom. The candidate who answers "fix it on write and add validation" understands the cost of letting bad data in.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Practice Advanced MongoDB Questions
&lt;/h2&gt;

&lt;p&gt;At this level, reading the answers is not enough. You need to test queries, inspect execution plans, and understand why MongoDB chooses one plan over another.&lt;/p&gt;

&lt;p&gt;Start with a real collection and run &lt;code&gt;explain('executionStats')&lt;/code&gt; on different queries. Compare &lt;code&gt;IXSCAN&lt;/code&gt;, &lt;code&gt;COLLSCAN&lt;/code&gt;, sort stages, documents examined, keys examined, and returned results. Then change the index and check what improves.&lt;/p&gt;

&lt;p&gt;You can also practice with aggregation pipelines, &lt;code&gt;$lookup&lt;/code&gt;, &lt;code&gt;$merge&lt;/code&gt;, and schema design patterns by building small examples and watching how the data changes at each step.&lt;/p&gt;

&lt;p&gt;For more practical workflows, you can explore the &lt;a href="https://visualeaf.com/docs" rel="noopener noreferrer"&gt;VisuaLeaf documentation&lt;/a&gt;, where MongoDB schema design, aggregation pipelines, indexes, and explain plans are explained visually.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Use This List
&lt;/h2&gt;

&lt;p&gt;For interviewers: pick 5,7 across categories , drag in one schema-design question, one indexing/performance question, one replication or sharding question, and at least one tactical "have you actually shipped this" question. That mix surfaces the difference between a candidate who knows the docs and one who has been on call for a Mongo cluster at 3 AM.&lt;/p&gt;

&lt;p&gt;For candidates: the lowest-leverage thing to study at this level is more operators. The highest-leverage is reading &lt;code&gt;explain()&lt;/code&gt; output until every stage name makes sense, then doing the same with &lt;code&gt;serverStatus()&lt;/code&gt; and &lt;code&gt;db.collection.stats()&lt;/code&gt;. The senior interview signal is debugging vocabulary , you don't need to remember every flag, but you need to be able to say "I'd check the cache hit rate and the index size relative to RAM" and have someone nod.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>database</category>
      <category>developers</category>
    </item>
    <item>
      <title>Top MongoDB Interview Questions For Beginners in 2026</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Tue, 02 Jun 2026 09:03:32 +0000</pubDate>
      <link>https://dev.to/visualeaf/top-mongodb-interview-questions-for-beginners-in-2026-428b</link>
      <guid>https://dev.to/visualeaf/top-mongodb-interview-questions-for-beginners-in-2026-428b</guid>
      <description>&lt;p&gt;A practical guide for junior and mid-level engineers preparing for MongoDB interviews. The questions here cover the concepts you're expected to know cold: BSON, documents, indexing basics, the aggregation operators that come up most, and the query patterns that separate "wrote a tutorial app" from "shipped a Mongo-backed feature."&lt;/p&gt;

&lt;p&gt;If you can answer these without rehearsing — and explain the &lt;em&gt;why&lt;/em&gt; — you'll handle the early rounds of any MongoDB interview. The harder material (storage internals, sharding, replication trade-offs, production tactics) lives in the companion advanced article.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Fundamentals
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q1. What is BSON and how is it different from JSON?
&lt;/h3&gt;

&lt;p&gt;BSON ("Binary JSON") is the binary-encoded format MongoDB uses on the wire and on disk. The differences that actually matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More types.&lt;/strong&gt; JSON has &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;array&lt;/code&gt;, &lt;code&gt;object&lt;/code&gt;. BSON adds &lt;code&gt;ObjectId&lt;/code&gt;, &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;Decimal128&lt;/code&gt;, &lt;code&gt;Binary&lt;/code&gt;, &lt;code&gt;Int32&lt;/code&gt; vs &lt;code&gt;Int64&lt;/code&gt; vs &lt;code&gt;Double&lt;/code&gt;, &lt;code&gt;Timestamp&lt;/code&gt;, &lt;code&gt;Regex&lt;/code&gt;, &lt;code&gt;MinKey&lt;/code&gt;/&lt;code&gt;MaxKey&lt;/code&gt;, etc. — so a &lt;code&gt;Decimal128&lt;/code&gt; survives a round-trip; a JSON number doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-describing and length-prefixed.&lt;/strong&gt; Every document and every field starts with its byte length, so the driver can skip fields without parsing them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordered fields.&lt;/strong&gt; BSON preserves insertion order of keys. JSON objects technically don't.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cost: BSON is usually slightly larger than the equivalent JSON because of the type tags and length prefixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q2. Document, collection, database — define them.
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Document&lt;/strong&gt;: a BSON object, up to 16 MB. Roughly equivalent to a row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collection&lt;/strong&gt;: a set of documents. Schemaless by default but you can attach a &lt;code&gt;$jsonSchema&lt;/code&gt; validator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: a namespace of collections. A single MongoDB deployment can have many databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A frequent follow-up: &lt;em&gt;why 16 MB?&lt;/em&gt; The limit exists to discourage "row-as-blob" patterns and to keep wire-protocol messages bounded. If you legitimately need bigger objects, use GridFS (which chunks across documents).&lt;/p&gt;

&lt;h3&gt;
  
  
  Q3. What's an &lt;code&gt;_id&lt;/code&gt; field? Can I change it?
&lt;/h3&gt;

&lt;p&gt;Every document has a unique &lt;code&gt;_id&lt;/code&gt; within its collection; it's the implicit primary key and is automatically indexed. If you don't supply one, the driver generates an &lt;code&gt;ObjectId&lt;/code&gt; (12 bytes: 4 timestamp, 5 random, 3 counter). You can use any BSON type as &lt;code&gt;_id&lt;/code&gt; — UUIDs, strings, even subdocuments — but &lt;strong&gt;&lt;code&gt;_id&lt;/code&gt; is immutable&lt;/strong&gt;. To "change" it you have to insert a new document and delete the old one (ideally in a transaction).&lt;/p&gt;

&lt;h3&gt;
  
  
  Q4. What does single-document atomicity mean in practice?
&lt;/h3&gt;

&lt;p&gt;Every write to a single document is atomic, even across embedded subdocuments and arrays. &lt;code&gt;$set&lt;/code&gt;, &lt;code&gt;$inc&lt;/code&gt;, &lt;code&gt;$push&lt;/code&gt;, etc., on the same document in one update apply as a unit — no partial state visible to other readers.&lt;/p&gt;

&lt;p&gt;That's the most underused feature in MongoDB schema design. If you embed related data, you get transactional updates for free, without reaching for multi-document transactions.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Schema Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q5. Embed or reference?
&lt;/h3&gt;

&lt;p&gt;The most common interview question, and the one that gets the worst answers. The honest rule of thumb:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Embed&lt;/strong&gt; when the related data is accessed together, has bounded growth, and doesn't need to be queried independently. Example: an order with its line items.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference&lt;/strong&gt; when the related data is large, unbounded, shared across multiple parents, or queried on its own. Example: products referenced by many orders; users referenced by audit events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 16 MB document limit forces a decision when arrays grow — &lt;em&gt;unbounded&lt;/em&gt; one-to-many is the classic embedding mistake. If "how many of these per parent?" has no ceiling, reference.&lt;/p&gt;

&lt;p&gt;A useful middle ground is the &lt;strong&gt;extended reference&lt;/strong&gt;: store just the fields you need from the referenced doc (&lt;code&gt;{userId, userName}&lt;/code&gt; instead of the whole user), trading consistency for read speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q6. What is &lt;code&gt;$jsonSchema&lt;/code&gt; validation?
&lt;/h3&gt;

&lt;p&gt;Per-collection schema rules MongoDB enforces on write. Set with &lt;code&gt;db.runCommand({collMod: 'users', validator: {$jsonSchema: {...}}})&lt;/code&gt;. Validation levels are &lt;code&gt;strict&lt;/code&gt; (default — every insert/update validated) or &lt;code&gt;moderate&lt;/code&gt; (only docs that already matched the schema get re-validated on update). Validation action is &lt;code&gt;error&lt;/code&gt; (reject) or &lt;code&gt;warn&lt;/code&gt; (log).&lt;/p&gt;

&lt;p&gt;It's optional, but extremely useful for enforcing invariants without giving up flexibility — the "schemaless" reputation MongoDB has does &lt;em&gt;not&lt;/em&gt; mean you can't enforce a schema when you want to.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Indexing Basics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q7. What index types does MongoDB support, and when do you use each?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single field&lt;/strong&gt; — the default. Indexes one field, ascending or descending.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compound&lt;/strong&gt; — multiple fields. Order matters; follow the &lt;strong&gt;ESR rule&lt;/strong&gt; (next question). A compound index on &lt;code&gt;{a, b, c}&lt;/code&gt; supports queries on &lt;code&gt;{a}&lt;/code&gt;, &lt;code&gt;{a, b}&lt;/code&gt;, &lt;code&gt;{a, b, c}&lt;/code&gt; — but not &lt;code&gt;{b}&lt;/code&gt; or &lt;code&gt;{c}&lt;/code&gt; alone (this is the &lt;em&gt;prefix rule&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multikey&lt;/strong&gt; — automatic when you index an array field; one index entry per array element. Restriction: you can't create a compound index across two array fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text&lt;/strong&gt; — full-text search. One per collection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2dsphere&lt;/strong&gt; — geospatial queries (&lt;code&gt;$near&lt;/code&gt;, &lt;code&gt;$geoWithin&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hashed&lt;/strong&gt; — supports equality only, but is the basis of hashed sharding for even distribution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTL&lt;/strong&gt; — special single-field index with &lt;code&gt;expireAfterSeconds&lt;/code&gt; that auto-deletes old docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partial&lt;/strong&gt; — index only documents matching &lt;code&gt;partialFilterExpression&lt;/code&gt;. Smaller, cheaper, supports unique-on-subset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unique&lt;/strong&gt; — enforces uniqueness; pair with &lt;code&gt;partialFilterExpression&lt;/code&gt; if you need "unique when present."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sparse&lt;/strong&gt; — index only docs that have the field. Largely superseded by partial indexes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Q8. Explain the ESR rule.
&lt;/h3&gt;

&lt;p&gt;For compound indexes, put fields in this order to maximize use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Equality&lt;/strong&gt; predicates (&lt;code&gt;{ status: 'active' }&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sort&lt;/strong&gt; fields (so MongoDB can walk the index in order — no in-memory sort)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Range&lt;/strong&gt; predicates (&lt;code&gt;{ createdAt: { $gt: ... } }&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why: after a range scan the index is no longer ordered for subsequent fields, so anything after a range field in the index is wasted for sort purposes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q9. How do you tell if a query uses an index?
&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;coll&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="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="s1"&gt;executionStats&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;Look at &lt;code&gt;winningPlan.stage&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;IXSCAN&lt;/code&gt; — index scan. Good.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COLLSCAN&lt;/code&gt; — collection scan. Almost always bad on a non-trivial collection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FETCH&lt;/code&gt; over &lt;code&gt;IXSCAN&lt;/code&gt; — the query needed to fetch the full document after the index lookup. Acceptable, but a &lt;em&gt;covered query&lt;/em&gt; (next question) is faster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SORT&lt;/code&gt; after the IXSCAN — means MongoDB did an in-memory sort. Often a sign your index doesn't cover the sort.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key counters: &lt;code&gt;totalKeysExamined&lt;/code&gt; vs &lt;code&gt;totalDocsExamined&lt;/code&gt; vs &lt;code&gt;nReturned&lt;/code&gt;. The ideal ratio is &lt;code&gt;keysExamined ≈ docsExamined ≈ nReturned&lt;/code&gt;. If &lt;code&gt;docsExamined&lt;/code&gt; &amp;gt;&amp;gt; &lt;code&gt;nReturned&lt;/code&gt;, you're scanning too much.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q10. What is a covered query?
&lt;/h3&gt;

&lt;p&gt;A query is &lt;em&gt;covered&lt;/em&gt; when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;All fields used in the filter and the projection are in the same index.&lt;/li&gt;
&lt;li&gt;No field in the projection is missing from the index.&lt;/li&gt;
&lt;li&gt;You explicitly exclude &lt;code&gt;_id&lt;/code&gt; (&lt;code&gt;{_id: 0, name: 1}&lt;/code&gt;) unless &lt;code&gt;_id&lt;/code&gt; is in the index.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A covered query never fetches the document — it returns straight from the index. Major win for read-heavy paths.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Querying
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Q11. &lt;code&gt;$lookup&lt;/code&gt; vs application-side joins?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;$lookup&lt;/code&gt; performs a left-outer join inside the aggregation pipeline. It works, but it's expensive — the joined collection is read repeatedly per pipeline document unless the foreign field is indexed. Practical rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The foreign field &lt;strong&gt;must&lt;/strong&gt; be indexed. Always.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$lookup&lt;/code&gt; after &lt;code&gt;$match&lt;/code&gt; and &lt;code&gt;$limit&lt;/code&gt;, never before — shrink the input first.&lt;/li&gt;
&lt;li&gt;Prefer the &lt;code&gt;pipeline&lt;/code&gt; form (&lt;code&gt;$lookup&lt;/code&gt; with &lt;code&gt;let&lt;/code&gt; + &lt;code&gt;pipeline&lt;/code&gt;) over the simple form when you want to push filters down into the join.&lt;/li&gt;
&lt;li&gt;For 1:1 reference lookups in a tight loop, an app-side &lt;code&gt;find({_id: {$in: [...]}})&lt;/code&gt; is sometimes faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Q12. What's the difference between &lt;code&gt;$match&lt;/code&gt; and &lt;code&gt;$project&lt;/code&gt; placement in a pipeline?
&lt;/h3&gt;

&lt;p&gt;Pipeline order matters because each stage's output is the next stage's input. Two principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Push &lt;code&gt;$match&lt;/code&gt; as early as possible so subsequent stages process fewer docs and can use an index (the query optimizer can move some &lt;code&gt;$match&lt;/code&gt; stages before a &lt;code&gt;$sort&lt;/code&gt; automatically, but not always).&lt;/li&gt;
&lt;li&gt;Push &lt;code&gt;$project&lt;/code&gt; early too — but only to &lt;em&gt;remove&lt;/em&gt; large unused fields, not to compute things. Computing then matching is wasted work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Q13. Walk me through &lt;code&gt;$group&lt;/code&gt;, &lt;code&gt;$bucket&lt;/code&gt;, &lt;code&gt;$facet&lt;/code&gt;.
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$group&lt;/code&gt;: classic SQL &lt;code&gt;GROUP BY&lt;/code&gt;. &lt;code&gt;{ $group: { _id: "$category", total: { $sum: "$price" } } }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$bucket&lt;/code&gt; / &lt;code&gt;$bucketAuto&lt;/code&gt;: groups documents into a defined set of ranges (histograms).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$facet&lt;/code&gt;: runs multiple sub-pipelines in parallel on the same input. The killer use case: returning both a paged result and a total count from one query.
&lt;/li&gt;
&lt;/ul&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;products&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="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;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shoes&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="na"&gt;$facet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;$sort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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;$skip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Q14. &lt;code&gt;$elemMatch&lt;/code&gt; — when do you need it?
&lt;/h3&gt;

&lt;p&gt;When you want array elements that match &lt;strong&gt;multiple criteria simultaneously&lt;/strong&gt; on the same element. The difference is subtle:&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="c1"&gt;// MATCHES if ANY element has score&amp;gt;80 OR ANY element has type='math'&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;students&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scores.score&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;$gt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scores.type&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;math&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// MATCHES only if SOME element has score&amp;gt;80 AND type='math' together&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;students&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;scores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$elemMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$gt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;math&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first one returns a student with a math score of 70 and an art score of 90. The second wouldn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q15. Pagination at scale — what's wrong with &lt;code&gt;skip&lt;/code&gt; + &lt;code&gt;limit&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;skip(N)&lt;/code&gt; walks N documents to discard them. At N=100,000 that's a real cost on every page, and it grows linearly. The standard fix is &lt;strong&gt;range-based&lt;/strong&gt; ("seek") pagination using the previous page's last sort key:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&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;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$lt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lastSeenCreatedAt&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="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&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;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the sort key has duplicates, fall back to a tie-breaker on &lt;code&gt;_id&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Q16. What's &lt;code&gt;findAndModify&lt;/code&gt; vs &lt;code&gt;updateOne&lt;/code&gt; + read?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;findOneAndUpdate&lt;/code&gt; (and the older &lt;code&gt;findAndModify&lt;/code&gt;) atomically reads and updates a document, returning either the pre- or post-update version. The point is to avoid a race between read and update — for things like counters, work queues, or any "find first pending and mark it taken" pattern.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Practice These Questions
&lt;/h2&gt;

&lt;p&gt;Reading the answers helps, but MongoDB starts to make more sense when you test things yourself.&lt;/p&gt;

&lt;p&gt;Try running a few real queries, then check the &lt;code&gt;explain()&lt;/code&gt; plan. See if MongoDB uses an &lt;code&gt;IXSCAN&lt;/code&gt; or a &lt;code&gt;COLLSCAN&lt;/code&gt;, compare how many documents were examined, and then create a different index to see what changes.&lt;/p&gt;

&lt;p&gt;You can do the same with aggregation stages like &lt;code&gt;$match&lt;/code&gt;, &lt;code&gt;$group&lt;/code&gt;, &lt;code&gt;$lookup&lt;/code&gt;, and &lt;code&gt;$facet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For more examples, you can also check the &lt;a href="https://visualeaf.com/docs" rel="noopener noreferrer"&gt;VisuaLeaf documentation&lt;/a&gt;, where MongoDB queries, indexes, schema design, and explain plans are explained with practical workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Go Next
&lt;/h2&gt;

&lt;p&gt;The questions above cover what entry-to-mid-level engineers are expected to know. The next layer — WiredTiger internals, replication trade-offs, sharding strategy, multi-document transactions, production profiling, schema migration patterns — is where senior interviews live. That material is in the companion article: &lt;em&gt;MongoDB Interview Questions for Advanced Engineers&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you can answer 80% of the questions in this list without rehearsing, the highest-leverage way to keep going is to run your own &lt;code&gt;explain()&lt;/code&gt; against a real dataset and read the output until every counter and stage name makes sense. That's the single biggest gap between "knows MongoDB" and "ships MongoDB."&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>database</category>
      <category>developers</category>
    </item>
    <item>
      <title>MongoDB `$facet` Explained: One Query, Multiple Results</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Fri, 29 May 2026 09:35:59 +0000</pubDate>
      <link>https://dev.to/visualeaf/mongodb-facet-explained-one-query-multiple-results-b64</link>
      <guid>https://dev.to/visualeaf/mongodb-facet-explained-one-query-multiple-results-b64</guid>
      <description>&lt;p&gt;Sometimes one MongoDB aggregation needs to return more than one result.&lt;/p&gt;

&lt;p&gt;For example, from the same &lt;code&gt;payments&lt;/code&gt; collection, you may want revenue by payment method, total revenue, and the latest paid payments.&lt;/p&gt;

&lt;p&gt;You could write separate aggregations for each one. But &lt;code&gt;$facet&lt;/code&gt; lets you keep them in the same pipeline.&lt;/p&gt;

&lt;p&gt;It takes the same input documents and sends them through smaller pipelines. Each one returns its own result.&lt;/p&gt;

&lt;p&gt;That is why &lt;code&gt;$facet&lt;/code&gt; is useful for dashboards, reports, filters, and analytics pages.&lt;/p&gt;

&lt;p&gt;MongoDB describes &lt;code&gt;$facet&lt;/code&gt; as a way to run multiple aggregation pipelines in one stage on the same input documents. You can read more in the official &lt;a href="https://www.mongodb.com/docs/manual/reference/operator/aggregation/facet/" rel="noopener noreferrer"&gt;MongoDB documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frgufhykcjqag8moo40ui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frgufhykcjqag8moo40ui.png" alt="MongoDB $facet diagram showing payments filtered with $match and split into byMethod, revenueSummary, and latestPayments." width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Payments Example
&lt;/h2&gt;

&lt;p&gt;For this example, we will use a &lt;code&gt;payments&lt;/code&gt; collection.onA document may look like this:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;paidAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-05-20T10:30:00Z&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;Let’s say you want a small report on paid payments.&lt;/p&gt;

&lt;p&gt;You need revenue by payment method, total revenue, and the latest paid payments.&lt;/p&gt;

&lt;p&gt;All of these answers come from the same collection.&lt;/p&gt;

&lt;p&gt;That is where &lt;code&gt;$facet&lt;/code&gt; helps. You start with one filtered set of payments, then split it into different results.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt;, this is easier to follow because you can see the data first, then build the pipeline step by step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxipu4sj806ufjiwvnudp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxipu4sj806ufjiwvnudp.png" alt="Payments collection in VisuaLeaf showing fields like amount, method, currency, status, and paidAt." width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the Pipeline Visually
&lt;/h2&gt;

&lt;p&gt;Now, we can build the aggregation step by step.&lt;/p&gt;

&lt;p&gt;The first stage is &lt;code&gt;$match&lt;/code&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paid&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;This keeps only paid payments.&lt;/p&gt;

&lt;p&gt;It is better to filter the data before &lt;code&gt;$facet&lt;/code&gt;, because every branch will use the same clean input.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can see this directly in the preview. After the &lt;code&gt;$match&lt;/code&gt; stage, the output should show only documents where &lt;code&gt;status&lt;/code&gt; is &lt;code&gt;paid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5jvyzgs69z8kxs4v26c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5jvyzgs69z8kxs4v26c.png" alt="VisuaLeaf Aggregation Builder showing a $match stage that filters payments where status equals paid." width="800" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the &lt;code&gt;$facet&lt;/code&gt; Stage
&lt;/h2&gt;

&lt;p&gt;After filtering the payments, we can add &lt;code&gt;$facet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the part where the pipeline splits.&lt;/p&gt;

&lt;p&gt;Until now, the aggregation had one path. With &lt;code&gt;$facet&lt;/code&gt;, the same paid payments can go in a few different directions.&lt;/p&gt;

&lt;p&gt;For this example, I created three sections inside &lt;code&gt;$facet&lt;/code&gt;: &lt;code&gt;byMethod&lt;/code&gt;, &lt;code&gt;revenueSummary&lt;/code&gt;, and &lt;code&gt;latestPayments&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They all start from the same filtered payments. They just answer different questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. byMethod
&lt;/h3&gt;

&lt;p&gt;The first one is &lt;code&gt;byMethod&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here, the payments are grouped by &lt;code&gt;$method&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So instead of looking at every payment one by one, we can see how each payment method performed.&lt;/p&gt;

&lt;p&gt;For example, card payments may have one total, bank transfers another total, and PayPal another one.&lt;/p&gt;

&lt;p&gt;This branch also counts how many payments each method has.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5yrvqigwy9ewkcbv1ji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5yrvqigwy9ewkcbv1ji.png" alt="VisuaLeaf showing the byMethod $facet branch grouped by payment method." width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. revenueSummary
&lt;/h3&gt;

&lt;p&gt;The next one is &lt;code&gt;revenueSummary&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the quick summary of the paid payments.&lt;/p&gt;

&lt;p&gt;It gives the total revenue, the number of payments, and the average payment amount.&lt;/p&gt;

&lt;p&gt;After the values are calculated, &lt;code&gt;$project&lt;/code&gt; keeps the result clean. We do not need every internal field here. We only need the numbers that will be shown in the report.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz5mw5graue9sv796vcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz5mw5graue9sv796vcp.png" alt="VisuaLeaf showing the revenueSummary branch with total revenue, number of payments, and average payment." width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. latestPayments
&lt;/h3&gt;

&lt;p&gt;The last one is &lt;code&gt;latestPayments&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This branch is for the recent records.&lt;/p&gt;

&lt;p&gt;It sorts the paid payments by &lt;code&gt;paidAt&lt;/code&gt;, with the newest payments first. Then it keeps only a few results.&lt;/p&gt;

&lt;p&gt;That makes it useful for a small table, like “latest payments” in a dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ee0j8tibi5flaap395d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ee0j8tibi5flaap395d.png" alt="VisuaLeaf sorting paid payments by paidAt in descending order inside a $facet pipeline." width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the Final Result
&lt;/h2&gt;

&lt;p&gt;After the branches are ready, run the aggregation.&lt;/p&gt;

&lt;p&gt;The result will look different from a normal list of documents.&lt;/p&gt;

&lt;p&gt;Instead of getting only payments, you get one result with separate sections inside it.&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;byMethod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...],&lt;/span&gt;
  &lt;span class="nx"&gt;revenueSummary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...],&lt;/span&gt;
  &lt;span class="nx"&gt;latestPayments&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;Each section comes from one branch inside &lt;code&gt;$facet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;byMethod&lt;/code&gt; shows the grouped revenue by payment method.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;revenueSummary&lt;/code&gt; shows the main numbers.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;latestPayments&lt;/code&gt; shows the newest paid records.&lt;/p&gt;

&lt;p&gt;This is why &lt;code&gt;$facet&lt;/code&gt; works well for reports. You can prepare several parts of the same page from one aggregation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28e2vjxnrvy4tcavb8mz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28e2vjxnrvy4tcavb8mz.png" alt="VisuaLeaf showing the final $facet result with byMethod, revenueSummary, and latestPayments outputs." width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the Generated Query Code
&lt;/h2&gt;

&lt;p&gt;After building the pipeline visually, you can open the generated query code.&lt;/p&gt;

&lt;p&gt;This is useful because you can see the exact MongoDB aggregation behind the visual steps.&lt;/p&gt;

&lt;p&gt;In this example, the query looks like this:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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="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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paid&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="na"&gt;$facet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;byMethod&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;$group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$method&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;totalPayments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;totalAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$amount&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="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;$sort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;totalAmount&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;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;revenueSummary&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;$group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;totalRevenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$amount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;numberOfPayments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;averagePayment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$avg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$amount&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="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;$project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;totalRevenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;numberOfPayments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;averagePayment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$round&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="s2"&gt;$averagePayment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&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="na"&gt;latestPayments&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;$sort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;paidAt&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;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;$limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;$project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;paidAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the visual builder easier to trust. You are not locked into a hidden workflow. You can build the pipeline visually, then read, copy, or adjust the generated code when you need it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3p7ocr7qu55zxl19mf01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3p7ocr7qu55zxl19mf01.png" alt="VisuaLeaf showing generated query code for a MongoDB $facet aggregation." width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When This Is Useful
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;$facet&lt;/code&gt; makes sense when several results come from the same filtered data.&lt;/p&gt;

&lt;p&gt;In this example, everything starts with paid payments.&lt;/p&gt;

&lt;p&gt;From there, we get payment method totals, a revenue summary, and the latest payments.&lt;/p&gt;

&lt;p&gt;That is the kind of structure you often need in a dashboard or report.&lt;/p&gt;

&lt;p&gt;You do not need &lt;code&gt;$facet&lt;/code&gt; for every aggregation. If you only need one result, a normal pipeline is easier.&lt;/p&gt;

&lt;p&gt;But when the same data needs to answer a few different questions, &lt;code&gt;$facet&lt;/code&gt; keeps the logic in one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;$facet&lt;/code&gt; looks a little strange at first, but the idea is not hard.&lt;/p&gt;

&lt;p&gt;You start with one set of documents, then split that data into different results.&lt;/p&gt;

&lt;p&gt;In this example, we started with paid payments. From there, we got revenue by method, a revenue summary, and the latest payments.&lt;/p&gt;

&lt;p&gt;That is why &lt;code&gt;$facet&lt;/code&gt; is useful for reports and dashboards. You can prepare several parts of the same page from one aggregation.&lt;/p&gt;

&lt;p&gt;And when you build it visually, it is much easier to see what each branch is doing.&lt;/p&gt;

&lt;p&gt;You can also try this in &lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt; if you want to see the pipeline step by step instead of reading only the code.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>developers</category>
      <category>database</category>
    </item>
    <item>
      <title>MongoDB vs PostgreSQL: What is the Difference?</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Tue, 26 May 2026 13:02:27 +0000</pubDate>
      <link>https://dev.to/visualeaf/mongodb-vs-postgresql-why-the-same-data-looks-so-different-9k0</link>
      <guid>https://dev.to/visualeaf/mongodb-vs-postgresql-why-the-same-data-looks-so-different-9k0</guid>
      <description>&lt;p&gt;When deciding between MongoDB and PostgreSQL, the biggest difference is how the data is organized.&lt;/p&gt;

&lt;p&gt;PostgreSQL is a strong choice when the data is structured and works well in related tables. MongoDB is often more suitable when the data is flexible, nested, or expected to evolve.&lt;/p&gt;

&lt;p&gt;Both databases are great, but they approach the same data in different ways.&lt;/p&gt;

&lt;p&gt;To make that easier to understand, the same clinic data is shown below in two forms: once as MongoDB documents and once as PostgreSQL tables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxxydhm6zlolz3shbozi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxxydhm6zlolz3shbozi.png" alt="MongoDB document model compared with PostgreSQL relational schema for clinic data" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same clinic data was modeled as a MongoDB document and a PostgreSQL relational schema.&lt;/p&gt;

&lt;p&gt;What Makes Them Different: Tables vs Documents&lt;/p&gt;

&lt;p&gt;This picture illustrates how the same data about ''&lt;strong&gt;clinic visits&lt;/strong&gt;'' looks in two database systems. In MongoDB, the information about visits is combined within one document, whereas PostgreSQL stores the data in separate tables.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Diagram Detail&lt;/th&gt;
&lt;th&gt;MongoDB&lt;/th&gt;
&lt;th&gt;PostgreSQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single &lt;code&gt;visits&lt;/code&gt; collection&lt;/td&gt;
&lt;td&gt;Multiple tables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;How the data is organized&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Patient, doctor, symptoms, prescriptions, and invoice are all included in &lt;strong&gt;one document&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Patients, doctors, appointments, prescriptions, and invoices are stored in &lt;strong&gt;separate tables&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data that is usually read together&lt;/td&gt;
&lt;td&gt;Data with strong relationships&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Example from the diagram&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One clinic visit contains nested details&lt;/td&gt;
&lt;td&gt;One appointment connects to a patient, doctor, prescriptions, and invoice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Main advantage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;It's easier to read a whole clinic visit in one place&lt;/td&gt;
&lt;td&gt;Relationships are clear and protected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What to be careful about&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Documents can become inconsistent or too large without good design&lt;/td&gt;
&lt;td&gt;Queries often need joins to bring related data together&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is the basic distinction between the two databases.&lt;/p&gt;

&lt;p&gt;In MongoDB, we start with the document.&lt;br&gt;&lt;br&gt;
In PostgreSQL, we start with the relationships.&lt;/p&gt;

&lt;p&gt;Both database models can represent the same clinic system, but the way you look at your data changes significantly.&lt;/p&gt;
&lt;h2&gt;
  
  
  SQL vs NoSQL Schema Design: Structure First vs Data First
&lt;/h2&gt;

&lt;p&gt;Another big difference is how the structure is created.&lt;/p&gt;

&lt;p&gt;In PostgreSQL, you first create the table. Then you insert the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;lab_results&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;result_id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;patient_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;test_name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;result_value&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;result_status&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the structure exists, you can insert rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;lab_results&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patient_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result_status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Anna Keller'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Blood Glucose'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'92 mg/dL'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'normal'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Matei Ionescu'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'White Blood Cells'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'12.1 x10^9/L'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'high'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the data appears in a table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdtz0t9ifu4asud0gz22e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdtz0t9ifu4asud0gz22e.png" width="590" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a visual database GUI, this process becomes easier to follow: first, the table is created, then rows are inserted, and finally, the data appears in table view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2uplpesrgo7rcxq4as4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2uplpesrgo7rcxq4as4t.png" alt="PostgreSQL example showing CREATE TABLE, INSERT INTO, and inserted rows in a table" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL requires the table structure before inserting data.&lt;/p&gt;

&lt;p&gt;MongoDB works differently. You can insert the document directly:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;labResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Anna Keller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;testName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Blood Glucose&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;resultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;92 mg/dL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;resultStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;normal&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;And the structure comes from the document you insert.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkxe0zb6w5el0w9chipa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkxe0zb6w5el0w9chipa.png" alt="MongoDB insertMany example showing lab results documents created after inserting data" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB creates the collection and document structure when data is inserted.&lt;/p&gt;

&lt;p&gt;In MongoDB, we do not need to create the collection structure first. When we insert the document, MongoDB creates the collection and stores the fields from the document.  &lt;/p&gt;

&lt;p&gt;So, in simple words:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;PostgreSQL&lt;/em&gt;&lt;/strong&gt;: create the structure first, then insert data.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;MongoDB&lt;/em&gt;&lt;/strong&gt;: insert the document first, and the structure appears from the data.&lt;/p&gt;

&lt;p&gt;If you want more control, MongoDB also lets you add &lt;em&gt;*&lt;strong&gt;&lt;em&gt;validation rules&lt;/em&gt;&lt;/strong&gt;*&lt;/em&gt; later. We explain this step by step in our article about &lt;a href="https://visualeaf.com/blog/mongodb-json-schema-validation/" rel="noopener noreferrer"&gt;MongoDB JSON Schema Validation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Querying: SQL JOINs vs Document-Based Querying
&lt;/h2&gt;

&lt;p&gt;The second difference after the storage is in querying.&lt;/p&gt;

&lt;p&gt;In PostgreSQL, data is stored in separate tables, which requires us to query using &lt;code&gt;JOIN&lt;/code&gt; to combine relevant data.&lt;/p&gt;

&lt;p&gt;For instance, if we would like to get clinic visits where both patients' and doctors' names are included, our query will be something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appointment_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;patient_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;doctor_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;specialization&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appointment_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;appointments&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;patients&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patient_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patient_id&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;doctors&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doctor_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doctor_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fci75wi99l03j2w9jo43u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fci75wi99l03j2w9jo43u.png" alt="PostgreSQL query in VisuaLeaf joining appointments, patients, and doctors, with combined results displayed in a table." width="800" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL JOIN query combining appointments, patients, and doctors.&lt;/p&gt;

&lt;p&gt;When using MongoDB, the data is stored close together within the document. Therefore, you would not need to join multiple tables, as the following MongoDB command can be used to obtain the information:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visits&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;doctor.specialization&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="s2"&gt;Cardiology&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="s2"&gt;completed&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78cgrbwfz6pbq6c31pu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78cgrbwfz6pbq6c31pu2.png" alt="MongoDB query in VisuaLeaf filtering clinic visits by doctor specialization and status, with results shown in Tree View." width="800" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB query result showing a nested clinic visit document.&lt;/p&gt;

&lt;p&gt;If you need the entire visit record containing all the required data, it would make sense to choose this approach.&lt;/p&gt;

&lt;p&gt;MongoDB can also join data when needed, using stages like &lt;code&gt;$lookup&lt;/code&gt; or &lt;code&gt;$graphLookup&lt;/code&gt; in the aggregation pipeline, but in many document models, the goal is to store related data together when it is usually read together.&lt;/p&gt;

&lt;p&gt;Here are the key differences to remember:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;PostgreSQL&lt;/em&gt;&lt;/strong&gt; relies on joins to obtain related data.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;MongoDB&lt;/em&gt;&lt;/strong&gt; queries documents containing all the related data.&lt;/p&gt;
&lt;h2&gt;
  
  
  Transactions and ACID: Saving Changes Safely
&lt;/h2&gt;

&lt;p&gt;A transaction means that several database changes are treated as one safe operation.&lt;/p&gt;

&lt;p&gt;Think about a clinic visit. When the visit is finished, the system may need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mark the visit as completed&lt;/li&gt;
&lt;li&gt;save the prescription&lt;/li&gt;
&lt;li&gt;create the invoice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Such operations have something in common. If one operation fails to complete, the whole group of operations should be rolled back, not just a part of them.&lt;/p&gt;

&lt;p&gt;The logic of ACID transactions lies right there: *&lt;strong&gt;&lt;em&gt;Either all is saved, or nothing is changed at all&lt;/em&gt;&lt;/strong&gt;*.&lt;/p&gt;
&lt;h3&gt;
  
  
  Transaction in PostgreSQL
&lt;/h3&gt;

&lt;p&gt;As we know, PostgreSQL separates data into different tables. Therefore, a transaction is able to update multiple related tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;appointments&lt;/span&gt;  
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt;  
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;appointment_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;prescriptions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appointment_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;medication_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dosage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration_days&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Skin cream'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Apply twice daily'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;invoices&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appointment_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payment_status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  

&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, PostgreSQL updates the appointment, adds the prescription, and creates the invoice as one operation.&lt;/p&gt;

&lt;p&gt;You can check the result with a query like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flidejpl3wdcg9batg6q3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flidejpl3wdcg9batg6q3.png" alt="PostgreSQL transaction result showing appointment, prescription, and invoice" width="800" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL transaction result showing appointment, prescription, and invoice.&lt;/p&gt;

&lt;p&gt;After the transaction runs, the appointment is marked as completed, the prescription is added, and the invoice is created.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transaction in MongoDB
&lt;/h3&gt;

&lt;p&gt;In this case, for the database MongoDB, the update is more straightforward since the data is within the same document.&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;visitId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VIS-1003&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;$set&lt;/span&gt;&lt;span class="p"&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="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="na"&gt;prescriptions&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;medicationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Skin cream&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="na"&gt;dosage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Apply twice daily&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="na"&gt;durationDays&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="p"&gt;],&lt;/span&gt;  
&lt;span class="na"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;95.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="na"&gt;paymentStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="na"&gt;issuedAt&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This update is for a one-visit document. The status, prescriptions, and invoices are saved in the same document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0lfo7tmimuz450x4tft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0lfo7tmimuz450x4tft.png" alt="MongoDB update result showing completed visit with prescription and invoice" width="800" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB update result showing the visit document updated in one place.&lt;/p&gt;

&lt;p&gt;It is possible to have multi-document transactions in MongoDB. However, since the relevant visit information is kept in the same document, one document is enough.&lt;/p&gt;

&lt;p&gt;Hence, it is not because only PostgreSQL uses transaction management.&lt;/p&gt;

&lt;p&gt;Transaction management is available in both PostgreSQL and MongoDB.&lt;/p&gt;

&lt;p&gt;The critical point is that transaction management will be required for PostgreSQL because the data is stored in separate tables, whereas in MongoDB, all relevant data may be put in one document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance: Which One Is Faster?
&lt;/h2&gt;

&lt;p&gt;Many people ask which solution will give them more speed. The answer is not straightforward.&lt;/p&gt;

&lt;p&gt;MongoDB is not faster in every case. PostgreSQL is not faster in every case either.&lt;/p&gt;

&lt;p&gt;Both solutions can work fast, and both can work slowly.&lt;/p&gt;

&lt;p&gt;It depends on the model design, the way you write the queries, and whether the right indexes are present.&lt;/p&gt;

&lt;p&gt;To make this more practical, I used the same question in both databases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Show completed cardiology visits.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;&lt;em&gt;PostgreSQL&lt;/em&gt;&lt;/strong&gt;, the query joins the &lt;code&gt;appointments&lt;/code&gt;, &lt;code&gt;patients&lt;/code&gt;, and &lt;code&gt;doctors&lt;/code&gt; tables to build the result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4btxwz4s8sec7u1znz3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4btxwz4s8sec7u1znz3.png" alt="PostgreSQL EXPLAIN ANALYZE plan in VisuaLeaf for a clinic query joining appointments, patients, and doctors." width="800" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PostgreSQL query plan for finding completed cardiology visits through related tables.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In &lt;strong&gt;&lt;em&gt;MongoDB&lt;/em&gt;&lt;/strong&gt;, the result can be read from the &lt;code&gt;visits&lt;/code&gt; collection, because the visit details are stored inside the document.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpgikvbronlvcvae840j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frpgikvbronlvcvae840j.png" alt="MongoDB query analysis in VisuaLeaf showing index usage for completed cardiology visits." width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB query analysis for finding completed cardiology visits in one collection.&lt;/p&gt;

&lt;p&gt;This is not meant to prove that one database is always faster. The example is small, and real performance depends on the amount of data, indexes, schema design, and query patterns.&lt;/p&gt;

&lt;p&gt;But it shows the idea clearly: PostgreSQL often builds the answer by connecting tables, while MongoDB can read related data from one document when the model is designed that way.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Which solution is faster?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You should ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Which database suits the way my app reads and writes data?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question is more useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling: Expanding from 2 TB to 4 TB
&lt;/h2&gt;

&lt;p&gt;When talking about scaling, we discuss how we should help our database support larger volumes, more users, or an increasing number of requests.&lt;/p&gt;

&lt;p&gt;One possible analogy may look like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What will happen when our database grows from 2 TB to 4 TB?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When it comes to expanding PostgreSQL, most often we start with &lt;strong&gt;&lt;em&gt;scaling up&lt;/em&gt;&lt;/strong&gt;. We mean that we make our primary server even stronger by adding more computing power, additional memory, etc. Also, read replicas may be used, but our core database is still built around the single main server.&lt;/p&gt;

&lt;p&gt;As far as scaling MongoDB, it is done with &lt;strong&gt;&lt;em&gt;scaling out&lt;/em&gt;&lt;/strong&gt;, using the technique called sharding. Here, the data is distributed between different servers.&lt;/p&gt;

&lt;p&gt;Let us take, for instance, our &lt;code&gt;visits&lt;/code&gt; collection. It may stay the same collection; however, its documents will be spread between several shards. Which shard will store which documents depends on the chosen shard key, e.g., &lt;code&gt;clinicId&lt;/code&gt;, &lt;code&gt;region&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbe4i5fn76s96w63q5a16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbe4i5fn76s96w63q5a16.png" alt="PostgreSQL vs MongoDB scaling" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL usually scales by making one main server stronger, while MongoDB can scale by spreading one collection across multiple shards.&lt;/p&gt;

&lt;p&gt;As you see, the difference lies in:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;PostgreSQL grows through expanding the primary database.&lt;/em&gt;&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;MongoDB can scale by distributing its documents across multiple servers.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But it does not mean we should use MongoDB solely because of its scalability.&lt;/p&gt;

&lt;p&gt;Some projects will never require any form of sharding. But PostgreSQL is also capable of handling extremely large datasets with proper indexing, partitioning, replicas, and other techniques.&lt;/p&gt;

&lt;p&gt;However, the more pertinent question is whether or not:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Do I need one strong relational system, or do I expect my data to be distributed across multiple servers?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For this comparison, I used &lt;strong&gt;&lt;em&gt;VisuaLeaf&lt;/em&gt;&lt;/strong&gt;, a GUI tool that works with both NoSQL and SQL databases. It helped me view MongoDB documents and PostgreSQL tables in the same workspace. You can download it here: &lt;a href="https://visualeaf.com/" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;Download for Free&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Which One Should You Choose?
&lt;/h2&gt;

&lt;p&gt;Go with &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;PostgreSQL&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; if you have structured and relational data, and it relies heavily on rules.&lt;/p&gt;

&lt;p&gt;When PostgreSQL is the best choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use tables with foreign keys&lt;/li&gt;
&lt;li&gt;apply joins&lt;/li&gt;
&lt;li&gt;make transactions&lt;/li&gt;
&lt;li&gt;generate reports&lt;/li&gt;
&lt;li&gt;have consistency of the data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use &lt;a href="https://www.mongodb.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;MongoDB&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; if you have flexible and nested data and it is more convenient to work with documents.&lt;/p&gt;

&lt;p&gt;When MongoDB is better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use JSON documents&lt;/li&gt;
&lt;li&gt;have flexible fields&lt;/li&gt;
&lt;li&gt;have nested structure&lt;/li&gt;
&lt;li&gt;change the structure fast&lt;/li&gt;
&lt;li&gt;have data that is used together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, there is no question about which database management system is better.&lt;/p&gt;

&lt;p&gt;You should choose the one that corresponds to how your application works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;MongoDB and PostgreSQL both provide solutions for similar issues but through entirely separate paths.&lt;/p&gt;

&lt;p&gt;After building the same clinic example in both databases, the difference becomes pretty obvious: PostgreSQL makes the relationships visible, while MongoDB makes the full visit easier to read in one place.&lt;/p&gt;

&lt;p&gt;If you want to read more practical MongoDB guides, you can find them here: &lt;a href="https://visualeaf.com/blog/" rel="noopener noreferrer"&gt;MongoDB Articles&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>postgres</category>
      <category>nosql</category>
      <category>sql</category>
    </item>
    <item>
      <title>Free MongoDB GUI Tool for Developers, Students, and Teams</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Mon, 25 May 2026 07:35:36 +0000</pubDate>
      <link>https://dev.to/visualeaf/free-mongodb-gui-tool-for-developers-students-and-teams-44la</link>
      <guid>https://dev.to/visualeaf/free-mongodb-gui-tool-for-developers-students-and-teams-44la</guid>
      <description>&lt;p&gt;MongoDB is much easier to understand when you can actually see your data, not just read it on a screen.&lt;/p&gt;

&lt;p&gt;The whole point of &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt; is to make this happen.&lt;/p&gt;

&lt;p&gt;VisuaLeaf gives you a way to work with MongoDB that's easy to look at, and it still uses the real MongoDB syntax. You can look at your databases, open up collections, check out the documents, run queries, change values, and use the MongoDB shell when you need to be in control.&lt;/p&gt;

&lt;p&gt;This is really helpful for students who are learning MongoDB, for developers who are testing data on their computers, or for anyone who wants a better way to look at their MongoDB collections.&lt;/p&gt;

&lt;p&gt;The VisuaLeaf Community Edition has all the tools you need to get your work done every day: it lets you connect to databases, browse collections, run queries, edit things, access the shell, and do basic database management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fchu2389qed1rz1zr7dlu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fchu2389qed1rz1zr7dlu.png" alt="VisuaLeaf showing a MongoDB students collection in Tree View with nested fields and indexes." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Connect to MongoDB
&lt;/h2&gt;

&lt;p&gt;The first step is to &lt;a href="https://visualeaf.com/features/connection-manager/" rel="noopener noreferrer"&gt;connect to your MongoDB instance.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can paste your MongoDB connection string. It will fill in the form for you. Then you can test if the connection works and save it for use. This method works for both MongoDB instances and remote clusters.&lt;/p&gt;

&lt;p&gt;Once you save the connection, your databases and collections will show up in the panel. You can then explore them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x1srd3r3ojmabko50qj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x1srd3r3ojmabko50qj.png" alt="VisuaLeaf new MongoDB connection window with connection string and authentication settings." width="800" height="729"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Browse collections visually
&lt;/h2&gt;

&lt;p&gt;After you connect, you can &lt;a href="https://visualeaf.com/docs/collection-view" rel="noopener noreferrer"&gt;open a collection&lt;/a&gt;, right from the sidebar.&lt;/p&gt;

&lt;p&gt;For example, if you open the &lt;code&gt;students&lt;/code&gt; collection, you will see all the documents in the workspace. You can expand each document. See the fields, values, and data types.&lt;/p&gt;

&lt;p&gt;This is really helpful because MongoDB documents can be complex. A document can have things like nested objects, lists, dates, and different types of values.&lt;/p&gt;

&lt;p&gt;When you expand everything step by step, the structure of the collection becomes much clearer with the &lt;code&gt;students&lt;/code&gt; collection and its documents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqavj65zlgnakresgd7g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqavj65zlgnakresgd7g.png" alt="VisuaLeaf showing a MongoDB students collection in Tree View with nested fields and indexes." width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Viewing in Tree, Table, JSON, and BSON modes
&lt;/h2&gt;

&lt;p&gt;Various operations require different views.&lt;/p&gt;

&lt;p&gt;When you need to analyze nested documents, Tree View will do the job. For comparing multiple documents, use Table View. JSON mode gives you an understanding of the document format, while MongoDB-specific datatypes are more easily analyzed using BSON.&lt;/p&gt;

&lt;p&gt;Therefore, instead of analyzing the same data set in one view only, you have access to all the available views depending on the operation performed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhv6ho24s773auzsx1iia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhv6ho24s773auzsx1iia.png" alt="VisuaLeaf showing a MongoDB collection in Table View with options to switch to Tree, JSON, and BSON." width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Run MongoDB queries
&lt;/h2&gt;

&lt;p&gt;When you have a collection open, you can look at the data you want by writing a MongoDB query in JSON format.&lt;/p&gt;

&lt;p&gt;For example, in a &lt;code&gt;students&lt;/code&gt; collection, you may want to find students from the Web Development program who are in year 1 or above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Web Development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"$gte"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, you are using MongoDB syntax, which is helpful if you are learning MongoDB queries.&lt;/p&gt;

&lt;p&gt;You are not just clicking buttons without knowing what is happening. You write the MongoDB query, run the MongoDB query, and then look at the results to see what the MongoDB query did.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finnvpj6w33crph5sba60.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finnvpj6w33crph5sba60.png" alt="VisuaLeaf showing a MongoDB JSON query and the matching results in Table View." width="799" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Run aggregation pipelines
&lt;/h2&gt;

&lt;p&gt;Sometimes a simple query is not enough. I need to do more with my data.&lt;/p&gt;

&lt;p&gt;Maybe I want to group documents count how many there are, sort them in a way or figure out some numbers like averages. That's where MongoDB aggregation pipelines come in handy.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf I can build an aggregation pipeline visually. I add stages like &lt;code&gt;Match&lt;/code&gt; &lt;code&gt;Group&lt;/code&gt; and &lt;code&gt;Sort&lt;/code&gt;. Then I configure each one. I can see the results as I go which is really helpful.&lt;/p&gt;

&lt;p&gt;For example lets say I have a &lt;code&gt;students&lt;/code&gt; collection. I can group students, by program, and calculate their average score.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"$match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"$group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$program"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"students"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"$sum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"averageScore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"$avg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$progress.averageScore"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"$sort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"students"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful because you do not read documents one by one. You start to understand patterns inside the data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqjc7772gsvg7w7dijph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqjc7772gsvg7w7dijph.png" alt="VisuaLeaf visual aggregation builder showing Match, Group, and Sort stages with live preview results." width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The results are shown to you in a way that makes it easier to follow what each stage of the data is doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Use the MongoDB shell when you want to write commands
&lt;/h2&gt;

&lt;p&gt;Use the MongoDB shell when you want to type commands.&lt;/p&gt;

&lt;p&gt;Some tasks still feel better when done from the shell.&lt;/p&gt;

&lt;p&gt;That is why VisuaLeaf lets you write MongoDB commands directly without leaving your workspace.&lt;/p&gt;

&lt;p&gt;For example you can type a command, like this:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;students&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;program&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Web Development&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="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;year&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="mi"&gt;1&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;This helps if you want to learn MongoDB syntax not just click through a visual interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2ivaecx7w8dbeg03qdf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2ivaecx7w8dbeg03qdf.png" alt="Mongodb Shell in VisuaLeaf " width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The difference is that you are not limited to the terminal. You can write a command, run it, and still look at your database visually in the tool.&lt;/p&gt;

&lt;p&gt;For beginners, this is a balance: you learn MongoDB commands and see your data at the same time.&lt;/p&gt;

&lt;p&gt;This way, you learn MongoDB.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Insert and edit documents
&lt;/h2&gt;

&lt;p&gt;A student document in MongoDB is usually stored in JSON format, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fullName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Grace Bennett"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"grace.bennett@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Web Development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"HTML"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CSS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JavaScript"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bristol"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"United Kingdom"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thing about JSON is that it is flexible. It can be really easy to make mistakes when you are editing it by hand. You have to be careful.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can open the student document in Tree View or Table View. Update the values directly. For example, if a student decides to change their specialization, you can change the &lt;code&gt;program&lt;/code&gt; field from &lt;code&gt;Web Development&lt;/code&gt; to &lt;code&gt;MongoDB Development&lt;/code&gt; without having to write an &lt;code&gt;updateOne()&lt;/code&gt; command in the shell.&lt;/p&gt;

&lt;p&gt;You can make changes by editing the value directly and then applying the update.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fxih61xlwueomria4za.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fxih61xlwueomria4za.png" alt="VisuaLeaf showing a MongoDB student document edited directly in Tree View." width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Create Databases and Collections Visually
&lt;/h2&gt;

&lt;p&gt;When you start a project, you usually need a database first, then a collection.&lt;/p&gt;

&lt;p&gt;You can make a database and a collection from the shell. It is easier to do it visually sometimes.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can make a database from the sidebar. Then you can make a collection using a form where you add the collection name, and that is it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xertvfh9d78ln7ny5he.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xertvfh9d78ln7ny5he.png" alt="VisuaLeaf dialog for creating a new MongoDB database" width="607" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For collections, you may only need a name for the collection, and you can also add a comment if you want to.&lt;/p&gt;

&lt;p&gt;This is especially helpful for people who are new to MongoDB because it shows the MongoDB structure more clearly:&lt;/p&gt;

&lt;p&gt;Database → Collection → Document&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscop20pc3pzurrwwm7jz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fscop20pc3pzurrwwm7jz.png" alt="VisuaLeaf Create Collection screen with basic setup, validation rules, advanced options, and time series settings." width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your project needs more control, you can also set up advanced options for the collection, such as capped collections, storage engine options, validation rules, index defaults, collation, views, or time series settings for the collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Create and view indexes
&lt;/h2&gt;

&lt;p&gt;Indexes are super important when your MongoDB queries start to slow down.&lt;/p&gt;

&lt;p&gt;When you do not have an index, MongoDB has to look through a lot of documents to find what you need. With the right index, MongoDB can find the data way faster.&lt;/p&gt;

&lt;p&gt;You can make an index in the MongoDB shell using &lt;code&gt;createIndex()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you often sort students by when they &lt;em&gt;*&lt;strong&gt;&lt;em&gt;joined&lt;/em&gt;&lt;/strong&gt;*&lt;/em&gt; and filter them by &lt;em&gt;*&lt;strong&gt;&lt;em&gt;program&lt;/em&gt;&lt;/strong&gt;*&lt;/em&gt; and &lt;em&gt;*&lt;strong&gt;&lt;em&gt;status&lt;/em&gt;&lt;/strong&gt;*&lt;/em&gt;, you can make an index like this:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIndex&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;program&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;joinedAt&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fad58eva7m11hewgmtlld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fad58eva7m11hewgmtlld.png" alt="VisuaLeaf showing a MongoDB createIndex command and the new index under the students collection." width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you make the index you can see it in the panel under the students collection.&lt;/p&gt;

&lt;p&gt;This is really helpful because you learn the MongoDB command and you also get to see which indexes are on the collection, in a visual way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is this free MongoDB GUI tool for?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;The VisuaLeaf Community Edition&lt;/a&gt;, is a great tool if you want a free and easy way to work with MongoDB.&lt;/p&gt;

&lt;p&gt;It is useful for people who want to make working with MongoDB simpler.&lt;/p&gt;

&lt;p&gt;It can help people like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a student who is learning MongoDB&lt;/li&gt;
&lt;li&gt;a developer who is testing data on their computer&lt;/li&gt;
&lt;li&gt;a backend developer who works with MongoDB collections every day&lt;/li&gt;
&lt;li&gt;someone who wants to look at documents without only using the command line&lt;/li&gt;
&lt;li&gt;someone who wants to look at, change, search, and make groups of data visually, and also make indexes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea of the VisuaLeaf Community Edition is simple: you still get to learn real MongoDB, but you get a visual workspace to work with MongoDB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It becomes easier to get clarity about the structure of data in MongoDB if it can be visually represented.&lt;/p&gt;

&lt;p&gt;Using VisuaLeaf Community Edition, you can connect to MongoDB and perform various operations like querying databases, building aggregations, executing shell commands, editing documents, creating collections, and viewing indexes on one screen.&lt;/p&gt;

&lt;p&gt;This makes it an effective free GUI for MongoDB that can be used by students and professionals for various purposes.&lt;/p&gt;

&lt;p&gt;In addition to this, VisuaLeaf offers you the facility to experience advanced functionality like its query builder and analytics dashboard free for 14 days.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>database</category>
      <category>data</category>
    </item>
    <item>
      <title>VisuaLeaf is mentioned in this article as one of the 7 best MongoDB tools tested.

Thank you!</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Fri, 08 May 2026 10:27:29 +0000</pubDate>
      <link>https://dev.to/visualeaf/visualeaf-is-mentioned-in-this-article-as-one-of-the-7-best-mongodb-tools-testedthank-you-20i5</link>
      <guid>https://dev.to/visualeaf/visualeaf-is-mentioned-in-this-article-as-one-of-the-7-best-mongodb-tools-testedthank-you-20i5</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/roxana_haidiner/best-mongodb-database-tools-in-2026-2i30" class="crayons-story__hidden-navigation-link"&gt;What is the Best MongoDB Database Tool in 2026?&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/roxana_haidiner" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2224346%2Ff71cca7a-b282-4793-a3ae-b04d89957d47.png" alt="roxana_haidiner profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/roxana_haidiner" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Roxana-Maria Haidiner
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Roxana-Maria Haidiner
                
              
              &lt;div id="story-author-preview-content-3625610" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/roxana_haidiner" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2224346%2Ff71cca7a-b282-4793-a3ae-b04d89957d47.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Roxana-Maria Haidiner&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/roxana_haidiner/best-mongodb-database-tools-in-2026-2i30" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 7&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/roxana_haidiner/best-mongodb-database-tools-in-2026-2i30" id="article-link-3625610"&gt;
          What is the Best MongoDB Database Tool in 2026?
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mongodb"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mongodb&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/database"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;database&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nosql"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nosql&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/roxana_haidiner/best-mongodb-database-tools-in-2026-2i30" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/roxana_haidiner/best-mongodb-database-tools-in-2026-2i30#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            12 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Automate MongoDB Exports, Imports, and Sync Jobs with VisuaLeaf</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Thu, 07 May 2026 21:00:00 +0000</pubDate>
      <link>https://dev.to/visualeaf/automate-mongodb-exports-imports-and-sync-jobs-with-visualeaf-476c</link>
      <guid>https://dev.to/visualeaf/automate-mongodb-exports-imports-and-sync-jobs-with-visualeaf-476c</guid>
      <description>&lt;p&gt;Not all MongoDB jobs are hard to perform since their implementation is usually not that complicated. But their frustration arises from having to do them time after time.&lt;/p&gt;

&lt;p&gt;Export the same collection.&lt;br&gt;
Import the other document into the database.&lt;br&gt;
Transfer the same set of data between environments.&lt;br&gt;
Do the job again the following week and then the next month.&lt;/p&gt;

&lt;p&gt;Now, the actual problem that you need to solve is not about figuring out how to execute the operation just once. It is about executing it in a &lt;strong&gt;reliable&lt;/strong&gt;, &lt;strong&gt;consistent&lt;/strong&gt; way, without having to rebuild the process over and over.&lt;/p&gt;

&lt;p&gt;This is exactly what &lt;a href="https://visualeaf.com/features/task-manager/" rel="noopener noreferrer"&gt;&lt;strong&gt;Task Manager&lt;/strong&gt;&lt;/a&gt; in VisuaLeaf allows for. Specifically, it is created to schedule and manage background jobs for &lt;strong&gt;exports, imports, sync jobs&lt;/strong&gt;, and any other recurring database operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fboext9ha45aqqo48uqck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fboext9ha45aqqo48uqck.png" alt="Task Manager gives you a central place to create, organize, and run recurring MongoDB jobs." width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When manual MongoDB work starts becoming a problem
&lt;/h2&gt;

&lt;p&gt;At first, performing operations manually doesn’t seem like such a big problem.&lt;/p&gt;

&lt;p&gt;You open the collection, perform the export/import/synchronization of your file, and continue working.&lt;/p&gt;

&lt;p&gt;However, after some time, the very process of doing this starts to create difficulties for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wasting time reinitializing your settings&lt;/li&gt;
&lt;li&gt;making it easy to miss a step&lt;/li&gt;
&lt;li&gt;relying too heavily on your own memory&lt;/li&gt;
&lt;li&gt;inability to track what happened once the operation was performed&lt;/li&gt;
&lt;li&gt;complications with performing the same operations in multiple environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is situations such as these that demonstrate the need for automation – not necessarily for the complexity that the latter implies, but simply because any repetitive task should eventually turn into a reusable process.&lt;/p&gt;

&lt;h3&gt;
  
  
  The way the VisuaLeaf Task Manager works
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt; Task Manager is not limited to scheduling a process at a specified time. This functionality is focused on performing repeatable actions with data, which makes it highly relevant to database operations.&lt;/p&gt;

&lt;p&gt;Export, import, and sync operations can be performed with the help of Task Manager; they are executed either once or regularly within certain time intervals ranging from hourly to monthly or even defined by cron expressions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqszwbv3u5jbuuplqhxgi.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqszwbv3u5jbuuplqhxgi.webp" alt="Task Manager showing recurring schedules: hourly, daily, weekly, monthly, and custom." width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, the user will know more about the process itself through access to information about the execution results, such as status, history, execution errors, number of processed and failing records, run time, and execution control tools such as starting, stopping, resuming, editing, duplicating, and deleting.&lt;/p&gt;

&lt;p&gt;Why do we need this feature? It makes the scheduler tool a part of the workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  An interesting real-world scenario: transferring a collection from one database to another.
&lt;/h2&gt;

&lt;p&gt;Another good example illustrating the value of Task Manager would be the process of transferring a collection from one database to another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjid4t20scupv2nadukco.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjid4t20scupv2nadukco.webp" alt="Setting up a collection sync job between MongoDB environments." width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This may be necessary to maintain synchronization between different environments, prepare a new test environment with a replica of production data, and other similar cases. Although the task itself is usually simple, performing such operations manually becomes tedious very quickly.&lt;/p&gt;

&lt;p&gt;Task Manager can be applied to address this issue since it allows treating data transfer operations as reusable processes rather than one-time tasks. You will be able to specify the source, target databases, and schedules only once, storing the configuration for further use. Then, you can perform the process repeatedly, make changes, create copies, and analyze results without having to start everything from scratch every single time.&lt;/p&gt;

&lt;h2&gt;
  
  
  However, Task Manager is useful not only for the migration of collections
&lt;/h2&gt;

&lt;p&gt;Besides the ability to migrate a collection between databases, there are other operational tasks that can be performed on the fly by Task Manager. These are:&lt;/p&gt;

&lt;h3&gt;
  
  
  Periodic exports
&lt;/h3&gt;

&lt;p&gt;Task Manager offers the possibility of exporting data in formats such as &lt;strong&gt;JSON&lt;/strong&gt;, &lt;strong&gt;CSV&lt;/strong&gt;, &lt;strong&gt;BSON&lt;/strong&gt;, and &lt;strong&gt;SQL INSERT commands&lt;/strong&gt;. That way, it may prove helpful during backups and reporting, during data handoffs or even migrations, if an external application relies either on receiving a file or SQL-like queries as input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx9d0wzk0180fhv18a30.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx9d0wzk0180fhv18a30.webp" alt="Creating a CSV export job in VisuaLeaf Task Manager." width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Periodic imports
&lt;/h3&gt;

&lt;p&gt;It also allows importing data in formats such as &lt;strong&gt;JSON&lt;/strong&gt;, &lt;strong&gt;CSV&lt;/strong&gt;, and &lt;strong&gt;BSON&lt;/strong&gt;, including the ability of performing transformations or mappings, and even using the upsert mode, which means updating the document if it already exists, rather than inserting it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyub74cjs5y3r651ewfca.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyub74cjs5y3r651ewfca.webp" alt="Setting up an import job in VisuaLeaf Task Manager." width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Synchronization workflows
&lt;/h3&gt;

&lt;p&gt;Task Manager may prove extremely useful for periodic synchronization scenarios, too, particularly for organizations relying on different environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The importance of monitoring on par with scheduling
&lt;/h2&gt;

&lt;p&gt;There is a variety of tools that help you schedule a particular job.&lt;/p&gt;

&lt;p&gt;That is not the important thing here.&lt;/p&gt;

&lt;p&gt;The real deal is what goes on once the job is started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it completed?&lt;/li&gt;
&lt;li&gt;Have there been any errors?&lt;/li&gt;
&lt;li&gt;How many documents have been processed?&lt;/li&gt;
&lt;li&gt;Have there been any misses?&lt;/li&gt;
&lt;li&gt;What is the duration of it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the most valuable functions of the feature. Task Manager allows you to track progress, view the execution history, monitor errors, status of tasks, and their stats, thus eliminating the guesswork about what has happened after each run.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flulx3z7kd4cbeepm1pn0.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flulx3z7kd4cbeepm1pn0.webp" alt="Tracking task history and success rates in VisuaLeaf Task Manager." width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Monitoring becomes an essential part of value here as jobs are being run weekly or even daily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Another reason this feature is practical: transformations
&lt;/h2&gt;

&lt;p&gt;Simple data scheduling can transfer data.&lt;/p&gt;

&lt;p&gt;A more advanced workflow tool will make it possible for you to work with your data while moving it.&lt;/p&gt;

&lt;p&gt;As we can see from the documentation, Task Manager allows for field mapping, type conversion, filtering, custom JavaScript transformations, and even aggregation pipeline processing before export.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsric84qk7aseoqyrkee.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsric84qk7aseoqyrkee.webp" alt="Creating a fullName field and previewing the result in the target collection." width="800" height="661"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is important because actual workflows are not about simply copying a collection. Instead, you often need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rename fields&lt;/li&gt;
&lt;li&gt;change types&lt;/li&gt;
&lt;li&gt;filter out unused records&lt;/li&gt;
&lt;li&gt;do partial exports&lt;/li&gt;
&lt;li&gt;clean data before migration rather than after&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that will save you much trouble later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  How this particular feature grows in value with time
&lt;/h2&gt;

&lt;p&gt;Some features seem useful from the very first moment that you use them.&lt;/p&gt;

&lt;p&gt;Task Manager is unique in its nature because it becomes even more useful the more frequently you repeat similar work of similar kind.&lt;/p&gt;

&lt;p&gt;First-time collection move does not mean that you need Task Manager.&lt;/p&gt;

&lt;p&gt;But the fifth one makes you think about its benefits.&lt;/p&gt;

&lt;p&gt;By the tenth move, you realize why it is the right thing for managing your MongoDB tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices for setting up recurring tasks
&lt;/h2&gt;

&lt;p&gt;Before turning a job into a recurring task, it is worth testing it manually first. It also makes sense to schedule heavier operations during off-peak hours, monitor the first runs carefully, and use incremental approaches when large datasets are involved.&lt;/p&gt;

&lt;p&gt;It makes sense because this demonstrates the actual purpose of Task Manager rather than simply showcasing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who does Task Manager benefit the most?
&lt;/h2&gt;

&lt;p&gt;While the obvious audience for this functionality is the developer community, this is not exclusively so.&lt;/p&gt;

&lt;p&gt;Task Manager can be particularly helpful for the following groups:&lt;/p&gt;

&lt;h3&gt;
  
  
  Teams who collaborate around MongoDB data
&lt;/h3&gt;

&lt;p&gt;For those on the team who find themselves exporting the database as a CSV or JSON file more than once, Task Manager provides an elegant way to eliminate redundancy.&lt;/p&gt;

&lt;h3&gt;
  
  
  People managing incoming files
&lt;/h3&gt;

&lt;p&gt;If you are working on the import of any files, the process of mapping and transforming the data takes on new importance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Users who prefer streamlined workflows
&lt;/h3&gt;

&lt;p&gt;Some people can work well within a purely manual framework. Some people would rather automate certain processes, minimize errors, and gain better insight into their operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/docs/task-manager" rel="noopener noreferrer"&gt;Task Manager&lt;/a&gt; is designed to help solve one of the most common challenges encountered when working with MongoDB: performing operations in an automated manner without relying on memory, repetitive actions, or having to reconstruct everything from scratch.&lt;/p&gt;

&lt;p&gt;When using VisuaLeaf, the feature enables automation for export, import, synchronization, and migration tasks, yet allows maintaining control over their execution.&lt;/p&gt;

&lt;p&gt;That is why it proves useful. Task Manager saves time and effort, yet also makes repeating your MongoDB work easy and controllable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try VisuaLeaf
&lt;/h2&gt;

&lt;p&gt;If you would like to try these scenarios for yourself, feel free to download VisuaLeaf at the link below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;Download VisuaLeaf&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  External resources
&lt;/h2&gt;

&lt;p&gt;To learn more about the mentioned MongoDB tools and concepts, you might consider these resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/database-tools/mongoimport/" rel="noopener noreferrer"&gt;MongoDB &lt;code&gt;mongoimport&lt;/code&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/database-tools/mongoexport/" rel="noopener noreferrer"&gt;MongoDB &lt;code&gt;mongoexport&lt;/code&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/manual/core/aggregation-pipeline/" rel="noopener noreferrer"&gt;MongoDB Aggregation Pipeline documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crontab.guru/" rel="noopener noreferrer"&gt;Crontab Guru - cron expression reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>automation</category>
      <category>database</category>
    </item>
    <item>
      <title>How to Optimize MongoDB Query Performance with Indexes</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Thu, 07 May 2026 15:30:00 +0000</pubDate>
      <link>https://dev.to/visualeaf/how-to-optimize-mongodb-query-performance-with-indexes-289m</link>
      <guid>https://dev.to/visualeaf/how-to-optimize-mongodb-query-performance-with-indexes-289m</guid>
      <description>&lt;p&gt;Not all slow MongoDB queries are bad queries.&lt;/p&gt;

&lt;p&gt;Sometimes the query is fine, but MongoDB does not have a good index to help with your filtering, sorting, and retrieving of the data&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll use &lt;strong&gt;payments&lt;/strong&gt; as an example of our database. The collection starts without a useful index for our query. We'll identify the slow operation, learn about the recommended index, explain why the compound index works, and manage it visually in &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegmux3qtvq7mtz4dk56e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegmux3qtvq7mtz4dk56e.png" alt="Payments collection in VisuaLeaf showing currency status amount and paidAt fields" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The workflow is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;slow query -&amp;gt; query profiler -&amp;gt; index recommendation -&amp;gt; compound index -&amp;gt; index manager&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can use the same workflow when your own MongoDB collections start to feel slow.&lt;/p&gt;

&lt;h2&gt;
  
  
  On this page
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Slow Query Problem&lt;/li&gt;
&lt;li&gt;The Payments Query We Want to Optimize&lt;/li&gt;
&lt;li&gt;Find the Slow Query in VisuaLeaf&lt;/li&gt;
&lt;li&gt;Read the Index Recommendation&lt;/li&gt;
&lt;li&gt;Why This Compound Index Works&lt;/li&gt;
&lt;li&gt;Check and Manage Indexes&lt;/li&gt;
&lt;li&gt;Indexing Mistakes to Avoid&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Slow Query Problem
&lt;/h2&gt;

&lt;p&gt;MongoDB can return results quickly when a collection is small.&lt;/p&gt;

&lt;p&gt;But as the collection grows, the same query can become slower. MongoDB may need to scan many documents, sort a large result set, or check fields that are not indexed.&lt;/p&gt;

&lt;p&gt;That extra work is the real problem.&lt;/p&gt;

&lt;p&gt;For example, this query looks simple:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paid&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;If the &lt;code&gt;status&lt;/code&gt; field has no useful index; MongoDB may scan the collection to find matching documents.&lt;/p&gt;

&lt;p&gt;This is called a collection scan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu97qjo3rcgik17kfb9bl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu97qjo3rcgik17kfb9bl.png" alt="MongoDB Explain Plan showing COLLSCAN for payments query filtered by status paid" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A collection scan is not always bad. On a tiny collection, it may not matter. On a large collection used by your app every day, it matters a lot.&lt;/p&gt;

&lt;p&gt;When you inspect a query plan, these stages are important:&lt;/p&gt;

&lt;p&gt;A common warning sign looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COLLSCAN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MongoDB scanned the collection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IXSCAN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MongoDB used an index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FETCH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MongoDB fetched documents after using an index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SORT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;MongoDB performed a sort operation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;totalDocsExamined: 50000
nReturned: 25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means MongoDB checked 50,000 documents to return only 25.&lt;/p&gt;

&lt;p&gt;The goal is not just to make the query look cleaner. The goal is to make MongoDB do less work.&lt;/p&gt;

&lt;p&gt;MongoDB explains the technical index behavior in the official &lt;a href="https://www.mongodb.com/docs/manual/indexes/" rel="noopener noreferrer"&gt;MongoDB Indexes documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Payments Query We Want to Optimize
&lt;/h2&gt;

&lt;p&gt;Now let’s use a more realistic query.&lt;/p&gt;

&lt;p&gt;Imagine you have a &lt;code&gt;payments&lt;/code&gt; collection, and you often need to find *&lt;strong&gt;&lt;em&gt;'paid'&lt;/em&gt;&lt;/strong&gt;* USD payments above a certain amount, sorted by the newest payment date.&lt;/p&gt;

&lt;p&gt;The query looks like this:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&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="s2"&gt;paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&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="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;paidAt&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;This query does four things:&lt;/p&gt;

&lt;p&gt;If your &lt;code&gt;payments&lt;/code&gt; collection has no useful index for this pattern, MongoDB has to work harder than necessary.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;What the query does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currency&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keeps only payments in USD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keeps only paid payments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keeps payments greater than or equal to 100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;paidAt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sorts newest payments first&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A single-field index can help with simple filters, but this query uses multiple fields.&lt;/p&gt;

&lt;p&gt;That is why a compound index makes more sense here. It can support the filter, sort, and range condition together.&lt;/p&gt;

&lt;p&gt;We will let VisuaLeaf recommend the exact index after we inspect the slow query.&lt;/p&gt;

&lt;p&gt;MongoDB documents compound indexes in the official &lt;a href="https://www.mongodb.com/docs/manual/core/indexes/index-types/index-compound/" rel="noopener noreferrer"&gt;Compound Indexes documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find the Slow Query in VisuaLeaf
&lt;/h2&gt;

&lt;p&gt;Do not create indexes because a field looks important.&lt;/p&gt;

&lt;p&gt;Find the slow query first. Then index the query pattern.&lt;/p&gt;

&lt;p&gt;Use the same payments query from the previous section in the Visual Query Builder. Add the filters for currency, status, and amount, then sort by paidAt descending.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, the Explain view shows the execution plan, scanned documents, returned documents, execution time, and index usage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9f8d9icplciqi8m8z8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9f8d9icplciqi8m8z8m.png" alt="MongoDB Explain Plan in VisuaLeaf Query Builder showing collection scan and documents examined" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If MongoDB scans many documents and returns only a few, the query probably needs a better index.&lt;/p&gt;

&lt;p&gt;You can also run the same check manually with &lt;code&gt;explain()&lt;/code&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&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="s2"&gt;paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&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="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;paidAt&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you read the result, check these values:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;What you check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;totalDocsExamined&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How many documents MongoDB scanned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nReturned&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How many documents MongoDB returned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;executionTimeMillis&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;How long the query took&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;winningPlan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Which execution plan MongoDB selected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Look for IXSCAN when MongoDB uses an index, and COLLSCAN when MongoDB scans the collection. For one query, the Explain view is enough.&lt;/p&gt;

&lt;p&gt;For repeated slow operations across collections, use &lt;a href="https://visualeaf.com/features/query-profiler/" rel="noopener noreferrer"&gt;VisuaLeaf Query Profiling&lt;/a&gt;. The profiler helps you see slow operations over time, not just one query you are testing manually.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywu7i3nutljt53y6dztg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywu7i3nutljt53y6dztg.png" alt="MongoDB Query Profiling Dashboard in VisuaLeaf showing slow operations" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB also provides database profiling features for slow operations. You can read more in the official &lt;a href="https://www.mongodb.com/docs/manual/tutorial/manage-the-database-profiler/" rel="noopener noreferrer"&gt;Database Profiler documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the Index Recommendation
&lt;/h2&gt;

&lt;p&gt;After you find the slow query, check which index would actually help.&lt;/p&gt;

&lt;p&gt;In this example, the &lt;code&gt;payments&lt;/code&gt; collection has no useful index for the query. VisuaLeaf detects repeated collection scans and recommends a &lt;strong&gt;&lt;em&gt;compound index&lt;/em&gt;&lt;/strong&gt; based on the fields used by the query.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftva42q5xsc0db2snnvzq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftva42q5xsc0db2snnvzq.png" alt="MongoDB index recommendations in VisuaLeaf showing the recommended compound index for the payments collection" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The recommendation for the &lt;strong&gt;&lt;em&gt;compound index&lt;/em&gt;&lt;/strong&gt; is:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIndex&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;paidAt&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;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&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;This is useful because the recommendation does not only say “add an index.”&lt;/p&gt;

&lt;p&gt;It shows the exact fields and the order.&lt;/p&gt;

&lt;p&gt;That order is the important part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Compound Index Works
&lt;/h2&gt;

&lt;p&gt;The recommended index matches the way the query filters and sorts the data.&lt;/p&gt;

&lt;p&gt;After creating the recommended index, run the same query again in the Explain view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F630gn3uwnaxf94iozl2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F630gn3uwnaxf94iozl2x.png" alt="MongoDB Explain Plan in VisuaLeaf showing IXSCAN and compound index usage for payments query" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating the compound index, VisuaLeaf shows that MongoDB uses the index for the payments query.&lt;/p&gt;

&lt;p&gt;Now MongoDB uses the compound index instead of scanning the full collection.&lt;/p&gt;

&lt;p&gt;The query first filters by currency and status, then sorts by paidAt, and also applies a range condition on amount.&lt;/p&gt;

&lt;p&gt;In simple terms:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Why it is in the index&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currency&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exact filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exact filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;paidAt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sort by newest payment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Range condition&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Check and Manage Indexes
&lt;/h2&gt;

&lt;p&gt;After you create an index, check what exists in the collection.&lt;/p&gt;

&lt;p&gt;Indexes are easy to add and easy to forget.&lt;/p&gt;

&lt;p&gt;Over time, a collection can collect old indexes, duplicate indexes, or indexes created for queries that no longer exist.&lt;/p&gt;

&lt;p&gt;Use the &lt;a href="https://visualeaf.com/docs/index-management" rel="noopener noreferrer"&gt;Index Manager&lt;/a&gt; to review the indexes on your collection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqk029jce4f2tylh1ebz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqk029jce4f2tylh1ebz.png" alt="MongoDB Index Manager in VisuaLeaf showing indexes for a payments collection" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Index Manager helps you check the index name, fields, type, size, usage, properties, and status.&lt;/p&gt;

&lt;p&gt;This helps you avoid creating the same index twice.&lt;/p&gt;

&lt;p&gt;It also helps you review old indexes when your application queries change.&lt;/p&gt;

&lt;p&gt;You can combine this workflow with the &lt;a href="https://visualeaf.com/features/visual-query-builder/" rel="noopener noreferrer"&gt;Visual Query Builder&lt;/a&gt;, &lt;a href="https://visualeaf.com/features/mongo-shell/" rel="noopener noreferrer"&gt;MongoDB Shell&lt;/a&gt;, &lt;a href="https://visualeaf.com/features/aggregation-pipeline/" rel="noopener noreferrer"&gt;Aggregation Pipeline Builder&lt;/a&gt;, and &lt;a href="https://visualeaf.com/features/chart-builder/" rel="noopener noreferrer"&gt;Charts and Dashboards&lt;/a&gt; when you need to test, analyze, and present your MongoDB data.&lt;/p&gt;

&lt;p&gt;If you prefer, you can create the index visually from the Index Manager instead of writing the command manually.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqxhffb0zne17a70ft0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqxhffb0zne17a70ft0n.png" alt="Create MongoDB index visually in VisuaLeaf Index Manager with field direction and index options" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Indexing Mistakes to Avoid
&lt;/h2&gt;

&lt;p&gt;Indexes help when they match your workload.&lt;/p&gt;

&lt;p&gt;They create problems when you add them without a reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating indexes for every field
&lt;/h3&gt;

&lt;p&gt;Do not index every field in the collection.&lt;/p&gt;

&lt;p&gt;Each index needs storage. Each index also adds work when MongoDB inserts, updates, or deletes documents.&lt;/p&gt;

&lt;p&gt;Create indexes for queries your application actually runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ignoring the sort
&lt;/h3&gt;

&lt;p&gt;A query may filter quickly but still sort slowly.&lt;/p&gt;

&lt;p&gt;Example:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;paidAt&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;A useful index is:&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIndex&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;paidAt&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;This supports the filter and the sort.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting fields in the wrong order
&lt;/h3&gt;

&lt;p&gt;A compound index is not only about choosing the right fields. The order matters too.&lt;/p&gt;

&lt;p&gt;For the payments query, starting with the *&lt;strong&gt;&lt;em&gt;amount&lt;/em&gt;&lt;/strong&gt;* is not as useful as starting with the *&lt;strong&gt;&lt;em&gt;currency&lt;/em&gt;&lt;/strong&gt;* and *&lt;strong&gt;&lt;em&gt;status&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;, because the *&lt;/em&gt;&lt;strong&gt;amount&lt;/strong&gt;** is a range condition.&lt;/p&gt;

&lt;p&gt;Same fields. Different order. Different performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keeping indexes you no longer use
&lt;/h3&gt;

&lt;p&gt;Your application changes.&lt;/p&gt;

&lt;p&gt;Your queries change.&lt;/p&gt;

&lt;p&gt;Your indexes should change too.&lt;/p&gt;

&lt;p&gt;Review unused indexes from time to time and remove the ones that no longer support real queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;MongoDB query optimization starts with the query pattern.&lt;/p&gt;

&lt;p&gt;Do not guess. Find the slow query first. Check whether MongoDB scans too many documents. Then create an index that matches how your query filters, sorts, and ranges over the data.&lt;/p&gt;

&lt;p&gt;For simple filters, a single field index may be enough.&lt;/p&gt;

&lt;p&gt;For queries like the &lt;code&gt;payments&lt;/code&gt; example, a compound index is usually better.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt;, you can detect slow queries, review index recommendations, and manage MongoDB indexes visually in one place.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>database</category>
      <category>development</category>
    </item>
  </channel>
</rss>
