<?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.us-east-2.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>How to Import JSON into MongoDB and Export to CSV with Data Masking</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Thu, 23 Jul 2026 09:20:23 +0000</pubDate>
      <link>https://dev.to/visualeaf/how-to-import-json-into-mongodb-and-export-to-csv-with-data-masking-58p4</link>
      <guid>https://dev.to/visualeaf/how-to-import-json-into-mongodb-and-export-to-csv-with-data-masking-58p4</guid>
      <description>&lt;p&gt;Every morning, an online store receives the previous day’s orders from a marketplace partner.&lt;/p&gt;

&lt;p&gt;The file comes in JSON format. The company needs to add those orders to its main MongoDB &lt;code&gt;orders&lt;/code&gt; collection. The sales manager also needs a CSV report that can be opened in Excel.&lt;/p&gt;

&lt;p&gt;That sounds like a small task. Import the file, copy the documents, export the report.&lt;/p&gt;

&lt;p&gt;But in practice, a few things can break the process.&lt;/p&gt;

&lt;p&gt;A date can be imported as a string. A field can have the wrong name. One batch may use &lt;code&gt;total&lt;/code&gt;, while the main collection uses &lt;code&gt;totalAmount&lt;/code&gt;. A temporary collection can keep old records and trigger duplicate key errors. A CSV export can create null values because the mapping points to fields that do not exist.&lt;/p&gt;

&lt;p&gt;And then there is customer data. The manager may need the sales numbers, but they probably do not need real customer names or internal customer IDs.&lt;/p&gt;

&lt;p&gt;This article walks through a real daily workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Import marketplace JSON
        ↓
Store the batch in a temporary MongoDB collection
        ↓
Copy the orders into the main orders collection
        ↓
Mask customer fields during export
        ↓
Create a CSV report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not just to move data from JSON to CSV. The goal is to make the process repeatable, easier to check, and safer to share.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8g992dpxpflixeleq9x2.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8g992dpxpflixeleq9x2.png" alt="VisuaLeaf Task Manager showing a MongoDB workflow that imports yesterday’s orders from JSON, adds them to the main orders collection, and exports a CSV report." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow
&lt;/h2&gt;

&lt;p&gt;The workflow has three jobs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Import Yesterday Orders
        ↓
Add Orders to Main
        ↓
Export Daily Sales Report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is the parent relationship between the jobs.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Add Orders to Main&lt;/code&gt; depends on &lt;code&gt;Import Yesterday Orders&lt;/code&gt;, so it only runs after the JSON file is imported successfully.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Export Daily Sales Report&lt;/code&gt; depends on &lt;code&gt;Add Orders to Main&lt;/code&gt;, so the CSV is created only after the main &lt;code&gt;orders&lt;/code&gt; collection has been updated.&lt;/p&gt;

&lt;p&gt;This prevents the report from being generated when data is missing or incomplete.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvxggmrnum09wzra7ibg.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvxggmrnum09wzra7ibg.png" alt="VisuaLeaf Task Manager table view showing a daily MongoDB workflow where the import job has no parent, the copy job depends on the import, and the CSV export depends on the copy job." width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The incoming JSON file
&lt;/h2&gt;

&lt;p&gt;The partner sends a file with yesterday’s completed orders.&lt;/p&gt;

&lt;p&gt;A single order looks 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;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ORD-2026-07-201"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customerId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CUST-1003"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customerName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sofia Rossi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"orderDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-21T08:20:00Z"&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;"completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"paymentStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"paid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"items"&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;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EL-002"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"productName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wireless Mouse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Electronics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"unitPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;24.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"lineTotal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;24.99&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;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EL-003"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"productName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mechanical Keyboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Electronics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"unitPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;79.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"lineTotal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;79.99&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;"itemsSummary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1x Wireless Mouse, 1x Mechanical Keyboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"itemCount"&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;"subtotal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;104.98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"discount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shippingFee"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;99.97&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"couponCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WELCOME10"&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;There are two fields worth pointing out here.&lt;/p&gt;

&lt;p&gt;The first is &lt;code&gt;items&lt;/code&gt;. This is the real order structure. It keeps each product as a nested object with its own SKU, quantity, price, and line total.&lt;/p&gt;

&lt;p&gt;The second is &lt;code&gt;itemsSummary&lt;/code&gt;. This is not as rich as the &lt;code&gt;items&lt;/code&gt; array, but it works better in a CSV report. Instead of putting a full JSON array into one spreadsheet cell, the manager sees a readable value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1x Wireless Mouse, 1x Mechanical Keyboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MongoDB handles nested arrays well. CSV does not. So for the database, keep the array. For the report, export the summary.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The first job imports the file into a temporary collection:&lt;br&gt;&lt;br&gt;
&lt;code&gt;online_store.daily_sales_import&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fns2vukq2ddqqaz5li67r.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fns2vukq2ddqqaz5li67r.png" alt="VisuaLeaf Task Manager import job configured to load a JSON file into the online_store.daily_sales_import MongoDB collection." width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use a temporary collection?
&lt;/h2&gt;

&lt;p&gt;The first job imports the JSON file into &lt;code&gt;online_store.daily_sales_import&lt;/code&gt; instead of writing directly to &lt;code&gt;orders&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This extra step is worth it.&lt;/p&gt;

&lt;p&gt;The file comes from another system. Even if the partner usually sends the correct structure, a single change can break your report. A field can be renamed. A value can arrive as text instead of a number. A date can be formatted differently. Or the import job can use an old field mapping from another file.&lt;/p&gt;

&lt;p&gt;The temporary collection gives you a place to check the batch before it becomes part of the main order history.&lt;/p&gt;

&lt;p&gt;If it keeps old documents, the next run may copy the same orders again. That can cause duplicate key errors later.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcqykslgrvrvu70gfnpxw.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcqykslgrvrvu70gfnpxw.png" alt="VisuaLeaf showing the daily_sales_import MongoDB collection with one imported order document expanded, including fields such as customerId, customerName, items, itemsSummary, and orderDate." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate field mappings every time the JSON structure changes
&lt;/h2&gt;

&lt;p&gt;This is the easiest step to skip, and it is also where a lot of bad imports start.&lt;/p&gt;

&lt;p&gt;When you select the JSON file, click:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate Field Mappings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this order file, the mapping should include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_id           → _id
orderId       → orderId
customerId    → customerId
customerName  → customerName
orderDate     → orderDate
status        → status
paymentStatus → paymentStatus
currency      → currency
items         → items
itemsSummary  → itemsSummary
itemCount     → itemCount
subtotal      → subtotal
discount      → discount
shippingFee   → shippingFee
totalAmount   → totalAmount
couponCode    → couponCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you do not regenerate the mappings, the job may reuse fields from an older import.&lt;/p&gt;

&lt;p&gt;For example, if the previous import was a customer file, the mapping may still expect fields like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;country
email
joinedAt
name
customerId
status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The import may still run. But the order fields will be missing, and the result will look wrong. You may see null values or documents that only contain a few shared fields like &lt;code&gt;customerId&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is not a MongoDB issue. It is a mapping issue.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frpztwq8l13bacqmnby5w.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frpztwq8l13bacqmnby5w.png" alt="VisuaLeaf field mappings for a MongoDB copy job." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Copy the batch into the main orders collection
&lt;/h2&gt;

&lt;p&gt;The second job copies documents from:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;into:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This job should use &lt;code&gt;Import Yesterday Orders&lt;/code&gt; as its parent.&lt;/p&gt;

&lt;p&gt;A simple configuration is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source: online_store.daily_sales_import
Target: online_store.orders
Mode: Insert or Append
Parent: Import Yesterday Orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use insert or append because you are adding new orders to the order history.&lt;/p&gt;

&lt;p&gt;Do not use replace mode on &lt;code&gt;orders&lt;/code&gt; unless you really want to overwrite the full collection.&lt;/p&gt;

&lt;p&gt;The main collection should keep all orders. The temporary collection should only hold the latest imported file.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjtg7s7u3lqcfy8s5phd8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjtg7s7u3lqcfy8s5phd8.png" alt="VisuaLeaf copy job from daily_sales_import to orders." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Duplicate key errors are useful, but they still need a fix
&lt;/h2&gt;

&lt;p&gt;If you run the same batch twice, MongoDB may return this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;E11000 duplicate key error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means MongoDB blocked a duplicate value for a unique field, often &lt;code&gt;_id&lt;/code&gt; or &lt;code&gt;orderId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is usually good. It stops the same order from being inserted twice.&lt;/p&gt;

&lt;p&gt;But in a daily workflow, the error also tells you something is wrong with the process.&lt;/p&gt;

&lt;p&gt;Common causes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The temporary collection was not cleared.
The same JSON file was imported twice.
The partner sent duplicate order IDs.
The copy job tried to insert records already present in orders.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In testing, the temporary collection is often the problem.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;daily_sales_import&lt;/code&gt; contains old records and new records, the copy job tries to insert all of them. MongoDB accepts the new ones and rejects the duplicates.&lt;/p&gt;

&lt;p&gt;The fix is simple: clear or replace the temporary collection before each new import.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvw2b97rdaaz1e01g8n0i.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvw2b97rdaaz1e01g8n0i.png" alt="VisuaLeaf Task Manager showing an E11000 duplicate key error during a MongoDB copy job." width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Export the weekly report from the main collection
&lt;/h2&gt;

&lt;p&gt;The company imports marketplace orders every day, so the main MongoDB &lt;code&gt;orders&lt;/code&gt; collection stays up to date.&lt;/p&gt;

&lt;p&gt;But the manager does not need a CSV file every morning. In this case, the manager needs a weekly sales report.&lt;/p&gt;

&lt;p&gt;That changes the source of the export job.&lt;/p&gt;

&lt;p&gt;If you export from &lt;strong&gt;daily_sales_import,&lt;/strong&gt; you export only the latest imported batch.&lt;/p&gt;

&lt;p&gt;If you export from &lt;strong&gt;orders&lt;/strong&gt;, you export the main order history, including the orders that were imported during the week.&lt;/p&gt;

&lt;p&gt;For this workflow, the export job uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source: online_store.orders
Output: weekly-sales-report-{{yyyy-MM-dd}}.csv
Parent: Add Orders to Main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parent relationship still matters. The weekly CSV should be created only after the latest imported orders have been added to the main &lt;code&gt;orders&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;This gives the manager one report with the updated sales data, instead of sending a separate file every day.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffcef2dva65u1pwqndjhj.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffcef2dva65u1pwqndjhj.png" alt="VisuaLeaf export job from MongoDB orders collection to a weekly CSV report." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mask customer data during export
&lt;/h2&gt;

&lt;p&gt;The manager needs sales data, but they do not need the real customer name or internal customer ID.&lt;/p&gt;

&lt;p&gt;Instead of changing the original MongoDB documents, the export job applies masking only in the CSV output.&lt;/p&gt;

&lt;p&gt;In this workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;customerId   → hash(value)
customerName → maskName(value)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the original data intact in MongoDB, while the exported report hides sensitive customer details.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnp5mjkvulbf1o4qx0p53.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnp5mjkvulbf1o4qx0p53.png" alt="VisuaLeaf export mappings with hash(value) and maskName(value) applied." width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What maskName(value) does
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://visualeaf.com/docs/data-masking" rel="noopener noreferrer"&gt;&lt;code&gt;maskName(value)&lt;/code&gt; transformation&lt;/a&gt; keeps the first character and replaces the rest with asterisks.&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 plaintext"&gt;&lt;code&gt;Alex Ionescu → A***********
Mia Thompson → M***********
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It does not create a fake name.&lt;/p&gt;

&lt;p&gt;It masks the original value. The report still has a customer-name column, but the real name is hidden.&lt;/p&gt;

&lt;p&gt;This is useful when the report needs to show that a customer exists, but not who the customer is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hash(value) does
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;hash(value)&lt;/code&gt; transformation changes the customer ID into a hashed value.&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 plaintext"&gt;&lt;code&gt;CUST-1002 → 043a5f9b...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same input should produce the same hashed output.&lt;/p&gt;

&lt;p&gt;That means the report can still show that two orders belong to the same customer without exposing the original customer ID.&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 plaintext"&gt;&lt;code&gt;Original customerId: CUST-1002
Masked customerId:   043a5f9b...

Original customerId: CUST-1002
Masked customerId:   043a5f9b...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful for analysis.&lt;/p&gt;

&lt;p&gt;The manager can group orders by the masked ID, but they cannot see the real internal ID.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv68luj2i7s4jcit6rjxp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv68luj2i7s4jcit6rjxp.png" alt="VisuaLeaf export mappings with hash(value) and maskName(value) applied." width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Schedule the workflow
&lt;/h2&gt;

&lt;p&gt;Once each job works on its own, schedule the full workflow.&lt;/p&gt;

&lt;p&gt;The final process is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Receive marketplace JSON
        ↓
Import the daily batch
        ↓
Add orders to MongoDB
        ↓
Mask customer details
        ↓
Export the CSV report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the schedule to run every morning at 09:00.&lt;/p&gt;

&lt;p&gt;The parent relationships keep the jobs in order.&lt;/p&gt;

&lt;p&gt;The report does not run before the copy job. The copy job does not run before the import job.&lt;/p&gt;

&lt;p&gt;That is the main reason to use a workflow instead of three separate jobs.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvt34ftngxxddmfe4bsw0.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvt34ftngxxddmfe4bsw0.png" alt="VisuaLeaf schedule dialog showing a daily 9 AM recurring job." width="799" height="685"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What this workflow actually solves
&lt;/h2&gt;

&lt;p&gt;This workflow is not only about converting JSON to CSV.&lt;/p&gt;

&lt;p&gt;It solves a real process that many teams deal with: marketplace data comes in one format, MongoDB stores the operational data, and the manager needs a spreadsheet they can review without seeing unnecessary customer details.&lt;/p&gt;

&lt;p&gt;In this setup, the daily JSON file is imported into &lt;code&gt;daily_sales_import&lt;/code&gt;. Then the new orders are copied into the main &lt;code&gt;orders&lt;/code&gt; collection. At the end, the weekly CSV report is created from the updated &lt;code&gt;orders&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;Before the CSV is exported, sensitive customer fields are masked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;customerName → A***********
customerId   → 043a5f9b...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original MongoDB documents stay complete. Only the exported report hides customer details.&lt;/p&gt;

&lt;p&gt;This makes the process repeatable, easier to check, and safer to share.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final result
&lt;/h2&gt;

&lt;p&gt;At the end, you have one scheduled workflow that handles the daily marketplace file and keeps MongoDB up to date.&lt;/p&gt;

&lt;p&gt;You avoid repeating the same import and export steps by hand. You reduce the chance of copying old batches again. You keep the report readable with fields like &lt;code&gt;itemsSummary&lt;/code&gt;. And you share the sales data without exposing the original customer identities.&lt;/p&gt;

&lt;p&gt;The small details still matter: generate the mappings when the JSON structure changes, keep field names consistent, store dates as &lt;code&gt;DATE_TIME&lt;/code&gt;, and preview the export before trusting the CSV.&lt;/p&gt;

&lt;p&gt;Once those pieces are set, the workflow is easier to run, easier to check, and safer to share.&lt;/p&gt;

&lt;p&gt;I built this example in &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt; using &lt;a href="https://visualeaf.com/features/task-manager/" rel="noopener noreferrer"&gt;Task Manager&lt;/a&gt; and export transformations.&lt;/p&gt;

&lt;p&gt;If you work with MongoDB imports, scheduled exports, or masked reports, you can try it here: &lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;https://visualeaf.com/download&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>database</category>
      <category>software</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How to Copy and Sync a Local MongoDB Collection to Atlas</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Mon, 20 Jul 2026 14:04:46 +0000</pubDate>
      <link>https://dev.to/visualeaf/how-to-copy-and-sync-a-local-mongodb-collection-to-atlas-9me</link>
      <guid>https://dev.to/visualeaf/how-to-copy-and-sync-a-local-mongodb-collection-to-atlas-9me</guid>
      <description>&lt;p&gt;Moving data from a local MongoDB database to Atlas usually means exporting files, importing them again, and repeating the same process when something changes.&lt;/p&gt;

&lt;p&gt;I wanted to test a simpler way in VisuaLeaf: copy a local collection to MongoDB Atlas and keep the Atlas collection updated automatically.&lt;/p&gt;

&lt;p&gt;For this example, I used a local &lt;code&gt;visits&lt;/code&gt; collection containing seven documents. The documents included ordinary fields, nested objects, arrays, dates, and ObjectIds, so I could also check whether the original MongoDB structure remained intact in Atlas.&lt;/p&gt;

&lt;p&gt;Here is the complete process, followed by an insert, update, and delete test.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I used
&lt;/h2&gt;

&lt;p&gt;My source and target were:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Connection&lt;/th&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;th&gt;Collection&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Local Replica Set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;database_compare_demo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;visits&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MongoDB Atlas&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;database_compare_demo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;visits_atlas_sync&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I used a different target collection name so I could verify the copied data without mixing it with anything already stored in Atlas.&lt;/p&gt;

&lt;p&gt;The local source was a replica set because continuous synchronization relies on MongoDB change streams. Change streams are available for replica sets and sharded clusters, not standalone MongoDB deployments. (&lt;a href="https://www.mongodb.com/docs/manual/changestreams/" rel="noopener noreferrer"&gt;MongoDB change streams&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;If the source is standalone, the job can still perform an initial copy, but it cannot continue watching for later changes.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fel4d5b2jahtrnq4ifit7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fel4d5b2jahtrnq4ifit7.png" alt="The local  raw `visits` endraw  collection before it was copied to Atlas." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The local &lt;code&gt;visits&lt;/code&gt; collection before it was copied to Atlas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing the Atlas connection
&lt;/h2&gt;

&lt;p&gt;Before creating the sync job, I made sure VisuaLeaf could write to my Atlas cluster.&lt;/p&gt;

&lt;p&gt;Before using a standard Atlas connection, I configured two access items:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A database user with permission to access the target database.&lt;/li&gt;
&lt;li&gt;My computer’s public IP address added to the project’s IP access list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Atlas database users are separate from the account used to sign in to the Atlas website. For this test, I used a database user with read and write access to &lt;code&gt;database_compare_demo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I added only my current IP address to the Atlas access list instead of allowing connections from every IP. Atlas only accepts standard client connections from addresses included in that list. (&lt;a href="https://www.mongodb.com/docs/atlas/mongo-shell-connection/" rel="noopener noreferrer"&gt;MongoDB Atlas connection prerequisites&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;From the Atlas cluster’s *&lt;strong&gt;&lt;em&gt;Connect&lt;/em&gt;&lt;/strong&gt;* window, I copied the driver connection string. Its general format was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mongodb+srv://&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@&amp;lt;cluster-host&amp;gt;/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used that URI to create a connection in VisuaLeaf and named it &lt;code&gt;MongoDB Atlas&lt;/code&gt;. I tested the connection before continuing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the sync job
&lt;/h2&gt;

&lt;p&gt;I opened *&lt;strong&gt;&lt;em&gt;Mongo Sync&lt;/em&gt;&lt;/strong&gt;* and created a new job with these details:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Job name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Local Visits to Atlas&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Copy local clinic visits to Atlas and keep later changes synchronized.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source connection&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Local Replica Set&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source database&lt;/td&gt;
&lt;td&gt;&lt;code&gt;database_compare_demo&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The source connection showed full change-stream support, which meant I could select Full sync later.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Futet1ywge0qu0vowdlph.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Futet1ywge0qu0vowdlph.png" alt="The local replica set and  raw `database_compare_demo` endraw  database selected as the source." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The local replica set and &lt;code&gt;database_compare_demo&lt;/code&gt; database selected as the source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping the local collection to Atlas
&lt;/h2&gt;

&lt;p&gt;In the Rules step, I added the Atlas connection as the target and configured one rule:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Target connection&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MongoDB Atlas&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target database&lt;/td&gt;
&lt;td&gt;&lt;code&gt;database_compare_demo&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source collection&lt;/td&gt;
&lt;td&gt;&lt;code&gt;visits&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target collection&lt;/td&gt;
&lt;td&gt;&lt;code&gt;visits_atlas_sync&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter&lt;/td&gt;
&lt;td&gt;Empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transformation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;None (pass-through)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I left the filter empty because I wanted all seven documents.&lt;/p&gt;

&lt;p&gt;I also used *&lt;strong&gt;&lt;em&gt;None (pass-through)&lt;/em&gt;&lt;/strong&gt;* instead of generating field mappings. Both sides were MongoDB, so I wanted to preserve each document exactly as it was, including its &lt;code&gt;_id&lt;/code&gt;, nested objects, arrays, dates, and optional fields.&lt;/p&gt;

&lt;p&gt;Field mappings are useful when renaming fields, changing types, masking values, or sending data into a different schema. They were unnecessary for this direct MongoDB-to-MongoDB copy.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5sik23zrxfj0d3idawy6.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5sik23zrxfj0d3idawy6.png" alt="The  raw `visits` endraw  collection mapped to  raw `visits_atlas_sync` endraw  with pass-through documents." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;visits&lt;/code&gt; collection mapped to &lt;code&gt;visits_atlas_sync&lt;/code&gt; with pass-through documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Full sync
&lt;/h2&gt;

&lt;p&gt;The Options step offered three modes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;When to use it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Initial Only&lt;/td&gt;
&lt;td&gt;Copies the documents that currently exist, then stops&lt;/td&gt;
&lt;td&gt;One-time collection copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incremental Only&lt;/td&gt;
&lt;td&gt;Watches only for changes made after the job starts&lt;/td&gt;
&lt;td&gt;The target is already populated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full sync&lt;/td&gt;
&lt;td&gt;Copies existing documents and then watches for later changes&lt;/td&gt;
&lt;td&gt;Initial copy plus continuous synchronization&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I selected *&lt;strong&gt;&lt;em&gt;Full sync&lt;/em&gt;&lt;/strong&gt;* and enabled Start sync immediately after creation.&lt;/p&gt;

&lt;p&gt;This mode first copies the seven documents already stored locally. After the initial phase finishes, it continues listening for new inserts, updates, and deletes.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffkkb4ugkbnseowrd2gl6.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffkkb4ugkbnseowrd2gl6.png" alt="Full sync copies existing documents and continues watching the local collection." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full sync copies existing documents and continues watching the local collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reviewing and launching the job
&lt;/h2&gt;

&lt;p&gt;The Review screen showed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Local Replica Set / database_compare_demo&lt;/code&gt; as the source;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MongoDB Atlas / database_compare_demo&lt;/code&gt; as the target;&lt;/li&gt;
&lt;li&gt;one rule from &lt;code&gt;visits&lt;/code&gt; to &lt;code&gt;visits_atlas_sync&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;no filter or transformation;&lt;/li&gt;
&lt;li&gt;Full sync with automatic start.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also estimated an initial copy of approximately seven 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzsxs3cu9wn3x2lsofapc.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzsxs3cu9wn3x2lsofapc.png" alt="The complete local-to-Atlas configuration before launching the job." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The complete local-to-Atlas configuration before launching the job.&lt;/p&gt;

&lt;p&gt;I clicked *&lt;strong&gt;&lt;em&gt;Create &amp;amp; launch&lt;/em&gt;&lt;/strong&gt;* and waited for the initial phase to finish. Once the monitor showed that the job was running and waiting for changes, I checked the Atlas collection directly.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4nmdoyzxh5vol2kh0z8a.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4nmdoyzxh5vol2kh0z8a.png" alt="The initial copy is complete and the job is monitoring later changes." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The initial copy is complete and the job is monitoring later changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying the initial copy in Atlas
&lt;/h2&gt;

&lt;p&gt;I opened &lt;code&gt;database_compare_demo.visits_atlas_sync&lt;/code&gt; on the Atlas connection and counted its documents:&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_atlas_sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;countDocuments&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result was &lt;code&gt;7&lt;/code&gt;, matching the local source collection.&lt;/p&gt;

&lt;p&gt;I also opened several documents and checked their BSON types. The ObjectIds, dates, nested patient and doctor objects, and arrays were preserved because the job used pass-through documents rather than converting them into a new schema.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqahb7ju8f9ooh4czebxp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqahb7ju8f9ooh4czebxp.png" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The initial count proved that the collection was copied. It did not yet prove that the Full sync job would handle later changes, so I tested each main operation separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 1: Inserting a new local document
&lt;/h3&gt;

&lt;p&gt;I inserted one clearly labeled test visit into the local source:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy3f1wjvd9t2bozeroukt.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy3f1wjvd9t2bozeroukt.png" alt="Insert a new document into the local connection." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Insert a new document into the local connection.&lt;/p&gt;

&lt;p&gt;Then I searched for the same &lt;code&gt;visitId&lt;/code&gt; in Atlas:&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_atlas_sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&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-ATLAS-TEST&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3091869bg990uofkm4ru.gif" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3091869bg990uofkm4ru.gif" alt="A new local visit appears automatically in the Atlas collection." width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new local visit appears automatically in the Atlas collection.&lt;/p&gt;

&lt;p&gt;The new document appeared in the target collection without restarting or recreating the job. The target count increased from seven to eight.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 2: Updating the local document
&lt;/h3&gt;

&lt;p&gt;Next, I updated both a top-level field and a nested field:&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-ATLAS-TEST&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;doctor.roomNumber&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;204&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;updatedAt&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I checked the Atlas document again:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fic7sucvfx38dsx3gud77.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fic7sucvfx38dsx3gud77.png" alt="Top-level and nested changes from the local document are visible in Atlas." width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Top-level and nested changes from the local document are visible in Atlas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 3: Deleting the local document
&lt;/h3&gt;

&lt;p&gt;Finally, I deleted the test document from the local collection:&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;deleteOne&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-ATLAS-TEST&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;I verified the target one more time:&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_atlas_sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;countDocuments&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-ATLAS-TEST&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdiimdu68xq4ruwp6xysc.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdiimdu68xq4ruwp6xysc.png" alt="Deleting the local test document removes its synchronized Atlas copy." width="799" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deleting the local test document removes its synchronized Atlas copy.&lt;/p&gt;

&lt;p&gt;The result returned to &lt;code&gt;0&lt;/code&gt;, and the full Atlas collection returned to seven documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this workflow is useful
&lt;/h2&gt;

&lt;p&gt;This type of Mongo Sync job makes sense when I want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;copy selected local collections to an Atlas development or staging environment;&lt;/li&gt;
&lt;li&gt;keep a cloud copy updated while continuing to write locally;&lt;/li&gt;
&lt;li&gt;move a collection without repeatedly exporting and importing JSON files;&lt;/li&gt;
&lt;li&gt;test an application against Atlas using recent local data;&lt;/li&gt;
&lt;li&gt;synchronize only the collections needed for a specific workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important word is *&lt;strong&gt;&lt;em&gt;selected&lt;/em&gt;&lt;/strong&gt;*. This was a collection-level sync, not a complete production migration.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgs5hoieozvptjgpsd2sy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgs5hoieozvptjgpsd2sy.png" alt="VisuaLeaf Mongo Sync monitor showing live inserts, updates, and deletes." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live MongoDB sync from local replica set to Atlas.&lt;/p&gt;

&lt;h2&gt;
  
  
  How this differs from other Atlas migration methods
&lt;/h2&gt;

&lt;p&gt;MongoDB provides other tools for different jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mongodump&lt;/code&gt; and &lt;code&gt;mongorestore&lt;/code&gt; are useful for a self-managed, one-time transfer using a BSON dump.&lt;/li&gt;
&lt;li&gt;Atlas Live Migration is designed for moving a deployment into Atlas and managing a production cutover with minimal downtime.&lt;/li&gt;
&lt;li&gt;This Mongo Sync workflow focuses on copying selected collections and continuing to apply their changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Atlas recommends its Live Migration workflow when performing a supported production migration. It uses MongoDB’s &lt;code&gt;mongosync&lt;/code&gt; technology underneath and includes a cutover process for redirecting applications to the Atlas destination. (&lt;a href="https://www.mongodb.com/docs/atlas/live-migration/" rel="noopener noreferrer"&gt;Atlas Live Migration&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I would not present a collection-level sync as a replacement for that process.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would still verify before using it in production
&lt;/h2&gt;

&lt;p&gt;This small test verified document copying and three change types. It did not test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;high write volume or very large collections;&lt;/li&gt;
&lt;li&gt;long network interruptions and recovery;&lt;/li&gt;
&lt;li&gt;schema changes while the job was running;&lt;/li&gt;
&lt;li&gt;independent writes made to both source and target;&lt;/li&gt;
&lt;li&gt;users, roles, indexes, validation rules, or other database metadata;&lt;/li&gt;
&lt;li&gt;a full application cutover from local MongoDB to Atlas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I treated the local collection as the source of truth and used an empty target collection. That kept the test easy to understand and avoided conflicts with existing Atlas documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;The first copy was easy to check: 7 local documents appeared in Atlas.&lt;/p&gt;

&lt;p&gt;But the more important part was what happened after that. When I inserted, updated, and deleted a local document, the same changes appeared in Atlas without exporting another file or recreating the job.&lt;/p&gt;

&lt;p&gt;Because both sides were MongoDB, I could use pass-through mode and keep the original document structure.&lt;/p&gt;

&lt;p&gt;For development, staging, testing, or selected collection sync, this is a practical way to move local MongoDB data to Atlas and keep it updated. For a full production migration, I would still follow MongoDB’s official migration process and plan the cutover separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Want to try it?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs7aaysdkhl0hzivzdm6k.png" alt="CTA Image" width="799" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/" rel="noopener noreferrer"&gt;Download for Free and test Mongo Sync with your own local MongoDB database and Atlas cluster.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/manual/changestreams/" rel="noopener noreferrer"&gt;MongoDB change streams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/atlas/mongo-shell-connection/" rel="noopener noreferrer"&gt;Connect to a MongoDB Atlas cluster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/atlas/security/add-ip-address-to-list/" rel="noopener noreferrer"&gt;Manage the Atlas IP access list&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/atlas/live-migration/" rel="noopener noreferrer"&gt;Atlas Live Migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/database-tools/mongorestore/" rel="noopener noreferrer"&gt;&lt;code&gt;mongorestore&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mongodb</category>
      <category>database</category>
      <category>software</category>
      <category>javascript</category>
    </item>
    <item>
      <title>7 MongoDB Query Mistakes That Return the Wrong Results</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Tue, 14 Jul 2026 09:39:05 +0000</pubDate>
      <link>https://dev.to/visualeaf/7-mongodb-query-mistakes-that-return-the-wrong-results-5faj</link>
      <guid>https://dev.to/visualeaf/7-mongodb-query-mistakes-that-return-the-wrong-results-5faj</guid>
      <description>&lt;p&gt;MongoDB queries look simple. You type a field, give it a value, hit run, and you get your data back.&lt;/p&gt;

&lt;p&gt;But just because a query runs without throwing an error doesn't mean it worked right. Sometimes you get a blank screen. Sometimes you get way too many records. Other times, the data looks fine at first glance, but it doesn't actually match what you asked for.&lt;/p&gt;

&lt;p&gt;Most of these slip-ups happen for one basic reason: the query structure doesn't match the way the data actually sits in the database.&lt;/p&gt;

&lt;p&gt;To show you what we mean, we’ll use a clinic database with a collection called &lt;code&gt;visits&lt;/code&gt;. Here is what a typical document looks like:&lt;/p&gt;

&lt;p&gt;JSON&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "_id": "6871b6f9c3f1d1a4c2a10001",
  "status": "completed",
  "visitDate": "2026-07-01T09:30:00.000Z",
  "patient": { "name": "Anna Keller", "age": 34 },
  "doctor": { "name": "Dr. James Carter", "specialty": "Cardiology" },
  "symptoms": ["cough", "fever"],
  "prescriptions": [
    { "name": "Ibuprofen", "active": false },
    { "name": "Paracetamol", "active": true }
  ],
  "invoice": { "paid": true, "method": "card", "total": 250 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run these examples right in the &lt;a href="https://visualeaf.com/blog/mongodb-shell-visual-output/" rel="noopener noreferrer"&gt;VisuaLeaf MongoDB Shell&lt;/a&gt;. Using visual tools makes a big difference because you can see exactly what MongoDB is returning in real time.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Forgetting the Curly Braces
&lt;/h2&gt;

&lt;p&gt;This is just a quick typo, but it breaks things right away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Mistake:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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="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;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;strong&gt;The Correct Query&lt;/strong&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiu7e84hx4awafe8ue9eq.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiu7e84hx4awafe8ue9eq.png" alt="MongoDB query examples showing common mistakes with $or, $in, arrays, dates, and text search in VisuaLeaf." width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;find()&lt;/code&gt; tool always expects an object. Even if you are only looking for one specific thing, you still need to wrap that condition in curly braces &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Treating &lt;code&gt;$or&lt;/code&gt; Like a Regular Object
&lt;/h2&gt;

&lt;p&gt;This one trips a lot of people up because the broken version looks like it should work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Mistake:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.visits.find({
  $or: {
    status: "completed",
    "invoice.paid": false
  }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$or expects an array of conditions, but this query gives it one object.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error will usually be something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MongoServerError: $or must be an array
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Correct Query&lt;/strong&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F42cfbhf55y928ge2j9yg.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F42cfbhf55y928ge2j9yg.png" alt="MongoDB Shell query using $or with separate conditions, showing matching visit records in VisuaLeaf Table View." width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first query is wrong because &lt;code&gt;$or&lt;/code&gt; needs an array, not one regular object.&lt;/p&gt;

&lt;p&gt;Each condition has to be written as its own object inside &lt;code&gt;[]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The corrected query returns visits where the status is &lt;code&gt;pending&lt;/code&gt; or &lt;code&gt;completed&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Querying Nested Fields Like They Are Flat
&lt;/h2&gt;

&lt;p&gt;MongoDB documents often have fields inside other fields.&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;visits&lt;/code&gt; collection, &lt;code&gt;doctor&lt;/code&gt; is an object:&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;doctor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dr. Michael Brown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;specialization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Neurology&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;strong&gt;Query to avoid:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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="na"&gt;doctor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Neurology&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;This asks MongoDB to find a &lt;code&gt;doctor&lt;/code&gt; field that is exactly &lt;code&gt;"Neurology"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;doctor&lt;/code&gt; is not a string. It is an object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better query:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;Neurology&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhs6po958xjoqt0qxj5dy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhs6po958xjoqt0qxj5dy.png" alt="MongoDB query for a nested doctor.specialization field shown in VisuaLeaf Tree View." width="799" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dot tells MongoDB to go inside the &lt;code&gt;doctor&lt;/code&gt; object and check the &lt;code&gt;specialization&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;So instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is the whole &lt;code&gt;doctor&lt;/code&gt; field equal to Neurology?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;you are asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is the doctor’s specialization Neurology?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Typing the Same Field Twice
&lt;/h2&gt;

&lt;p&gt;Say you want to find visits with doctors from Cardiology or Dermatology.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query to avoid:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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="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;Dermatology&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;strong&gt;Better query:&lt;/strong&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvo1fjvgc4mtvbocfj91y.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvo1fjvgc4mtvbocfj91y.png" alt="MongoDB Shell query using $in to search visits by multiple values in the same field, with results shown in VisuaLeaf Table View." width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In JavaScript and MongoDB, you should not reuse the same key within a single object.&lt;/p&gt;

&lt;p&gt;If you type &lt;code&gt;"doctor.specialization"&lt;/code&gt; twice, the second value can overwrite the first one. So MongoDB may only search for &lt;code&gt;Dermatology&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If one field can match more than one value, use &lt;code&gt;$in&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Treating Dates Like Plain Text
&lt;/h2&gt;

&lt;p&gt;Dates can look like regular text, but in MongoDB they are often stored as real Date values.&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;visits&lt;/code&gt; collection, the invoice date is stored inside the &lt;code&gt;invoice&lt;/code&gt; object:&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;invoice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;issuedAt&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-05-18T10:15: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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;So this query will not work as expected:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.visits.find({
  "invoice.issuedAt": "2026-05-18"
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This searches for a string, not a Date, so it will usually return nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better query:&lt;/strong&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faeb7guvs2u7ncb45nrsn.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faeb7guvs2u7ncb45nrsn.png" alt="MongoDB Shell query in VisuaLeaf using $gte and $lt with new Date() to find invoices issued on May 18, 2026, with the matching result shown in Table View." width="799" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This returns invoices created on May 18, 2026.&lt;/p&gt;

&lt;p&gt;The range matters because dates usually include time. A visit at &lt;code&gt;1:15 PM&lt;/code&gt; is still on May 18, but it is not equal to midnight.&lt;/p&gt;

&lt;p&gt;So instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is the date exactly &lt;code&gt;"2026-05-18"&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;you are asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is the date on or after May 18 and before May 19?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. Expecting Text Search to Work Automatically
&lt;/h2&gt;

&lt;p&gt;MongoDB does not search text like Google by default.&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;visits&lt;/code&gt; collection, the doctor name is stored 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;doctor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dr. Michael Brown&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;strong&gt;So this query will not work:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.visits.find({
  "doctor.fullName": "Michael"
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This searches for an exact value. MongoDB checks if &lt;code&gt;doctor.fullName&lt;/code&gt; is exactly &lt;code&gt;"Michael"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But the real value is &lt;code&gt;"Dr. Michael Brown"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better setup:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For text search, you need to create a text index first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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;createIndex&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.fullName&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;text&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;Then you can search inside the text field:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwptblq34hq57llfos5ra.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwptblq34hq57llfos5ra.png" alt="MongoDB Shell query in VisuaLeaf using $text search for “Michael,” with the matching doctor name shown in Table View." width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now MongoDB can search for the word &lt;code&gt;Michael&lt;/code&gt; inside the indexed field.&lt;/p&gt;

&lt;p&gt;The important part is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;$text&lt;/code&gt; search does not work unless the collection has a text index.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  7. Reading &lt;code&gt;$or&lt;/code&gt; Logic Backwards
&lt;/h2&gt;

&lt;p&gt;This query runs fine, but it is easy to read it *&lt;strong&gt;&lt;em&gt;the wrong way&lt;/em&gt;&lt;/strong&gt;*:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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="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;$or&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="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;Neurology&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invoice.paymentStatus&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;unpaid&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;This does &lt;strong&gt;not&lt;/strong&gt; mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed OR Neurology OR unpaid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It actually means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed AND (Neurology OR unpaid)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;status&lt;/code&gt; is outside the &lt;code&gt;$or&lt;/code&gt; block, MongoDB treats it as required.&lt;/p&gt;

&lt;p&gt;So MongoDB first looks for visits where &lt;code&gt;status&lt;/code&gt; is &lt;code&gt;completed&lt;/code&gt;. Then, from those visits, it checks if the doctor is specialized in &lt;code&gt;Neurology&lt;/code&gt; or the invoice is &lt;code&gt;unpaid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want all three conditions to be part of the OR logic, move &lt;code&gt;status&lt;/code&gt; inside the &lt;code&gt;$or&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better query:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;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="na"&gt;$or&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;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="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;Neurology&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invoice.paymentStatus&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;unpaid&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;Now the query means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed OR Neurology OR unpaid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same fields. Different structure. Different result.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzqjs8i0zq2a1mw1zswj8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzqjs8i0zq2a1mw1zswj8.png" alt="Side-by-side VisuaLeaf MongoDB Shell screenshot comparing two $or queries, showing how moving status inside the $or array returns more matching documents." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One More Thing to Do before Using Your Query
&lt;/h2&gt;

&lt;p&gt;A MongoDB query is only as good as your understanding of the underlying document structure.&lt;/p&gt;

&lt;p&gt;Before you spend hours rewriting a broken query, do one simple thing: &lt;a href="https://visualeaf.com/blog/how-to-explore-and-work-with-mongodb-data-visually/" rel="noopener noreferrer"&gt;&lt;strong&gt;Open a single raw document from your collection.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look closely at the exact spelling of field names.&lt;/li&gt;
&lt;li&gt;Check the data types (Are numbers stored as strings? Are dates stored as objects?).&lt;/li&gt;
&lt;li&gt;Map out your nested objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly where a visual tool like &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;&lt;strong&gt;VisuaLeaf&lt;/strong&gt;&lt;/a&gt; saves the day. Instead of guessing from your code editor, you can test your queries inside the built-in shell and instantly toggle over to the &lt;a href="https://visualeaf.com/features/browse-collections/" rel="noopener noreferrer"&gt;&lt;strong&gt;Table View&lt;/strong&gt; or &lt;strong&gt;Tree View&lt;/strong&gt;&lt;/a&gt; to see exactly how your documents are laid out in real-time. No more guessing.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>coding</category>
      <category>software</category>
      <category>database</category>
    </item>
    <item>
      <title>DBeaver Alternative for MongoDB Queries, Aggregations, and Visual Workflows</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Wed, 08 Jul 2026 13:29:52 +0000</pubDate>
      <link>https://dev.to/visualeaf/dbeaver-alternative-for-mongodb-queries-aggregations-and-visual-workflows-18gn</link>
      <guid>https://dev.to/visualeaf/dbeaver-alternative-for-mongodb-queries-aggregations-and-visual-workflows-18gn</guid>
      <description>&lt;p&gt;DBeaver is a strong tool if you work with many databases.&lt;/p&gt;

&lt;p&gt;It makes sense for teams using PostgreSQL, MySQL, SQL Server, Oracle, and MongoDB in the same place. But if most of your work is in MongoDB, the workflow matters more.&lt;/p&gt;

&lt;p&gt;DBeaver does support MongoDB, but according to its documentation, the MongoDB driver is available in Lite, Enterprise, and Ultimate editions only. So this is not about saying DBeaver cannot work with MongoDB. It can, if you pay for those versions.&lt;/p&gt;

&lt;p&gt;Many developers stick with DBeaver because they are comfortable writing SQL. But VisuaLeaf bridges that gap natively with its own &lt;a href="https://visualeaf.com/features/sql-mode/" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;SQL Mode&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;, allowing you to write standard SQL queries that automatically translate into optimized MongoDB syntax.&lt;/p&gt;

&lt;p&gt;The question is whether you want a broad database tool, or a workspace built more directly around MongoDB documents, queries, aggregations, schemas, and charts.&lt;/p&gt;

&lt;p&gt;That is where &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt; fits better.&lt;/p&gt;

&lt;p&gt;It is focused on &lt;a href="https://www.mongodb.com/" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt; workflows, not every database type at once.&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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Fvisualeaf-interface.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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Fvisualeaf-interface.png" alt="VisuaLeaf brings MongoDB queries, schema diagrams, charts, dashboards, and team workflows into one visual workspace.&lt;br&gt;
" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VisuaLeaf brings MongoDB queries, schema diagrams, charts, dashboards, and team workflows into one visual workspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why MongoDB Users May Want a Different Tool
&lt;/h2&gt;

&lt;p&gt;MongoDB work is usually more visual than people expect.&lt;/p&gt;

&lt;p&gt;You are not only reading rows, but you are also checking what is inside each document.&lt;/p&gt;

&lt;p&gt;You are opening nested objects, or you are filtering by fields that may or may not exist in every record.&lt;/p&gt;

&lt;p&gt;You are building aggregation pipelines and trying to understand what changes after each stage.&lt;/p&gt;

&lt;p&gt;A general database tool can help, but it may not always feel built for this kind of work.&lt;/p&gt;

&lt;p&gt;VisuaLeaf is designed for the daily MongoDB tasks that users actually repeat:&lt;/p&gt;

&lt;p&gt;-&amp;gt; querying data, reading documents, building aggregations, checking schemas, creating charts, and working with collections more visually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build MongoDB Queries Visually
&lt;/h2&gt;

&lt;p&gt;Writing MongoDB queries by hand is useful.&lt;/p&gt;

&lt;p&gt;But not every filter needs to start with code.&lt;/p&gt;

&lt;p&gt;Sometimes you just want to find documents where &lt;code&gt;status&lt;/code&gt; is &lt;code&gt;paid&lt;/code&gt;, sort them by date, limit the results, and check the output.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can &lt;a href="https://visualeaf.com/features/visual-query-builder/" rel="noopener noreferrer"&gt;build that query visually.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You add filters, combine conditions, sort results, and see the generated MongoDB query behind it.&lt;/p&gt;

&lt;p&gt;That last part matters.&lt;/p&gt;

&lt;p&gt;The tool does not hide the query from you. It helps you understand it.&lt;/p&gt;

&lt;p&gt;So if you are learning MongoDB, you can see how the query is created.&lt;/p&gt;

&lt;p&gt;And if you already know MongoDB, you can move faster without typing every condition from scratch.&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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Fquery-builder.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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Fquery-builder.png" alt="Build MongoDB queries visually and keep the generated code visible.&lt;br&gt;
" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build MongoDB queries visually and keep the generated code visible.&lt;/p&gt;

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

&lt;p&gt;Aggregation pipelines are powerful, but they can get hard to read fast.&lt;/p&gt;

&lt;p&gt;A pipeline with one &lt;code&gt;$match&lt;/code&gt; stage is simple.&lt;/p&gt;

&lt;p&gt;A pipeline with &lt;code&gt;$match&lt;/code&gt;, &lt;code&gt;$group&lt;/code&gt;, &lt;code&gt;$sort&lt;/code&gt;, &lt;code&gt;$project&lt;/code&gt;, &lt;code&gt;$lookup&lt;/code&gt;, and &lt;code&gt;$unwind&lt;/code&gt; is different.&lt;/p&gt;

&lt;p&gt;At that point, the problem is not only writing the syntax.&lt;/p&gt;

&lt;p&gt;The problem is knowing what happened to the data after each stage.&lt;/p&gt;

&lt;p&gt;VisuaLeaf lets you &lt;a href="https://visualeaf.com/features/aggregation-pipeline/" rel="noopener noreferrer"&gt;build aggregation pipelines visually&lt;/a&gt; and check the output as you go.&lt;/p&gt;

&lt;p&gt;You can add a stage, see the result, then continue.&lt;/p&gt;

&lt;p&gt;That makes it easier to find mistakes, test ideas, and explain the pipeline to someone else.&lt;/p&gt;

&lt;p&gt;You are not guessing what the pipeline does. You can see 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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Faggregation-builder.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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Faggregation-builder.png" alt="Build MongoDB aggregation pipelines step by step with live preview&lt;br&gt;
" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Read MongoDB Documents More Clearly
&lt;/h2&gt;

&lt;p&gt;MongoDB documents can be clean, but real data is often messy.&lt;/p&gt;

&lt;p&gt;A document may have nested fields, arrays, dates, ObjectIds, embedded data, and references to other collections.&lt;/p&gt;

&lt;p&gt;If everything is forced into a flat table, the structure can be hard to follow.&lt;/p&gt;

&lt;p&gt;VisuaLeaf gives you different ways to &lt;a href="https://visualeaf.com/features/browse-collections/" rel="noopener noreferrer"&gt;browse MongoDB data&lt;/a&gt;, so you can inspect documents without losing the shape of the data.&lt;/p&gt;

&lt;p&gt;You can look at the document structure, check nested values, and switch views depending on what you need.&lt;/p&gt;

&lt;p&gt;This is useful when you open a collection you did not create yourself.&lt;/p&gt;

&lt;p&gt;You should not have to guess what is inside the data. You should be able to see it clearly.&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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Ftree-view.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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Ftree-view.png" alt="Browse MongoDB collections in the 3 different view modes.&lt;br&gt;
" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Browse MongoDB collections in the 3 different view modes.&lt;/p&gt;

&lt;h2&gt;
  
  
  See the MongoDB Schema
&lt;/h2&gt;

&lt;p&gt;MongoDB is flexible, but that flexibility can make the structure harder to understand.&lt;/p&gt;

&lt;p&gt;In SQL, tables and foreign keys usually show the structure.&lt;/p&gt;

&lt;p&gt;In MongoDB, relationships may be embedded inside documents, stored as references, or only suggested by field names.&lt;/p&gt;

&lt;p&gt;VisuaLeaf helps by showing collections, fields, nested structures, and relationships in a &lt;a href="https://visualeaf.com/features/visual-schema/" rel="noopener noreferrer"&gt;visual schema diagram.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This helps when you are learning a project, documenting a database, or explaining the structure to someone else.&lt;/p&gt;

&lt;p&gt;Instead of opening collection after collection and trying to remember everything, you can see the schema in one place.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8ubuu6uxot6r6hbhh51z.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8ubuu6uxot6r6hbhh51z.png" alt="DBeaver MongoDB alternative for Schema Diagram" width="799" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visual schema diagrams make flexible NoSQL data easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn Query Results Into Charts
&lt;/h2&gt;

&lt;p&gt;Sometimes a result table is enough. Sometimes it is not.&lt;/p&gt;

&lt;p&gt;If you want to see payments by method, orders by status, revenue by month, or expenses by category, a chart is easier to understand.&lt;/p&gt;

&lt;p&gt;VisuaLeaf lets you turn &lt;a href="https://visualeaf.com/features/chart-builder/" rel="noopener noreferrer"&gt;MongoDB data into charts&lt;/a&gt; and dashboards without exporting the results into another tool.&lt;/p&gt;

&lt;p&gt;You can query the data, check the result, and build a chart from the same workflow.&lt;/p&gt;

&lt;p&gt;That makes it easier to understand patterns in the data, not just read raw 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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Fcharts-and-dashboards.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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Fcharts-and-dashboards.png" alt="Create charts and dashboards from real MongoDB data.&lt;br&gt;
" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create charts and dashboards from real MongoDB data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mongo Shell for Developers
&lt;/h2&gt;

&lt;p&gt;Visual tools are helpful, but developers still need direct access to the database.&lt;/p&gt;

&lt;p&gt;VisuaLeaf includes a &lt;a href="https://visualeaf.com/features/mongo-shell/" rel="noopener noreferrer"&gt;MongoDB shell&lt;/a&gt;, so you can run commands without leaving the workspace.&lt;/p&gt;

&lt;p&gt;You can test a &lt;code&gt;find()&lt;/code&gt; query, run an update, check an aggregation, or execute MongoDB commands directly with autocomplete and syntax highlighting.&lt;/p&gt;

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

&lt;p&gt;You can write commands when you need full control, then switch back to visual results, query building, schema views, or charts when they help.&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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Fmongo-shell.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%2Fvisualeaf.com%2Fblog%2Fcontent%2Fimages%2F2026%2F07%2Fmongo-shell.png" alt="Run MongoDB commands with autocomplete, syntax highlighting, and visual results.&lt;br&gt;
" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run MongoDB commands with autocomplete, syntax highlighting, and visual results.&lt;/p&gt;

&lt;h2&gt;
  
  
  DBeaver vs VisuaLeaf for MongoDB Users
&lt;/h2&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;DBeaver&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 access&lt;/td&gt;
&lt;td&gt;Available in Lite, Enterprise, and Ultimate&lt;/td&gt;
&lt;td&gt;Free Community Edition + 14-day Pro trial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query building&lt;/td&gt;
&lt;td&gt;SQL and JavaScript workflow&lt;/td&gt;
&lt;td&gt;Visual MongoDB query builder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregations&lt;/td&gt;
&lt;td&gt;Manual SQL or JavaScript workflow&lt;/td&gt;
&lt;td&gt;Visual aggregation builder with stage preview&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Charts&lt;/td&gt;
&lt;td&gt;Available in paid editions&lt;/td&gt;
&lt;td&gt;Charts and dashboards in Professional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Teams using many database types&lt;/td&gt;
&lt;td&gt;Developers focused on MongoDB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;DBeaver is stronger when you need one tool for many database systems.&lt;/p&gt;

&lt;p&gt;VisuaLeaf is a better fit when MongoDB is your main focus, and you want visual tools for queries, aggregations, schema, documents, and charts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;DBeaver is a practical choice if you need one tool for many databases.&lt;/p&gt;

&lt;p&gt;But if you came here looking for a DBeaver alternative for MongoDB, you probably care more about the MongoDB workflow than the number of databases a tool supports.&lt;/p&gt;

&lt;p&gt;That is where VisuaLeaf is different.&lt;/p&gt;

&lt;p&gt;It gives you a &lt;a href="https://visualeaf.com/features/" rel="noopener noreferrer"&gt;MongoDB-focused workspace&lt;/a&gt; for browsing collections, building visual queries, creating aggregation pipelines, using the shell, viewing schema structure, and turning results into charts. And these are only some of the features. VisuaLeaf also includes tools for indexes, validation rules, collection comparison, query profiling, dashboards, saved queries, and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;Try VisuaLeaf&lt;/a&gt; if you want a MongoDB workspace that feels more focused, visual, and easier to follow.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>database</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>MongoDB vs PostgreSQL: The Arguments Everyone Gets Wrong</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Wed, 08 Jul 2026 13:08:13 +0000</pubDate>
      <link>https://dev.to/visualeaf/mongodb-vs-postgresql-the-arguments-everyone-gets-wrong-36f9</link>
      <guid>https://dev.to/visualeaf/mongodb-vs-postgresql-the-arguments-everyone-gets-wrong-36f9</guid>
      <description>&lt;p&gt;Most of the Postgres vs Mongo arguments I see online are based on assumptions that are either super outdated or just kind of technically wrong. The same topics keep coming up over and over on reddit, youtube, or whatever, and I wanted to write some of them down.&lt;/p&gt;

&lt;h2&gt;
  
  
  "PostgreSQL JSONB is basically MongoDB"
&lt;/h2&gt;

&lt;p&gt;JSONB lets Postgres store documents, but it doesn't turn Postgres into a document database. Mongo's storage engine, replication, sharding, aggregation framework, indexing, update semantics, and query engine were all designed around documents from day one. JSONB is bolted onto a relational engine.&lt;/p&gt;

&lt;p&gt;It's still really useful. But "just use JSONB" is kind of like saying "just throw a truck bed on a sedan and now it's a pickup." Like, technically there's overlap, but they're still doing different things.&lt;/p&gt;

&lt;h2&gt;
  
  
  "MongoDB is schemaless"
&lt;/h2&gt;

&lt;p&gt;Actually, that's one of the most common misconceptions.&lt;/p&gt;

&lt;p&gt;Mongo lets you have flexible documents, but modern Mongo has schema validation, required fields, type enforcement, unique indexes, and most of the guardrails you'd want from a regular database.&lt;/p&gt;

&lt;p&gt;Most Mongo deployments that actually work in production aren't truly schema-free. They just enforce schema differently (usually at the app layer or with validators).&lt;/p&gt;

&lt;h2&gt;
  
  
  "MongoDB loses data"
&lt;/h2&gt;

&lt;p&gt;This one is basically a meme from like 2013.&lt;/p&gt;

&lt;p&gt;Back then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default durability settings were weaker&lt;/li&gt;
&lt;li&gt;A lot of deployments ran without replica sets&lt;/li&gt;
&lt;li&gt;Some people disabled journaling (which... yeah)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern Mongo defaults are way safer. You get journaling, replica sets, majority-acknowledged writes, multi-document transactions, point-in-time recovery, and distributed replication. The "MongoDB loses data" thing is mostly people repeating something they heard a decade ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  "MongoDB is only for lazy devs"
&lt;/h2&gt;

&lt;p&gt;There are a lot of really smart database engineers and architects working at companies that run Mongo at scale. Choosing the "correct" database  usually has to do with the workload, not with anyone being lazy, and some workloads just map to documents better than they map to normalized tables.&lt;/p&gt;

&lt;p&gt;The misconception usually comes from MongoDB's flexibility, plus developers designing their databases recklessly without thinking about the future. In Postgres, it's much harder to do that because of all its guardrails. But that doesn't mean MongoDB is for lazy developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Postgres is always better"
&lt;/h2&gt;

&lt;p&gt;That's... debatable. Postgres is one of the best databases ever made, and it's usually a safe default. I'm not arguing against that. But like everything in software engineering, databases are tools, not teams to root for.&lt;/p&gt;

&lt;p&gt;The question isn't "which one is better." It's "which one matches the workload better."&lt;/p&gt;

&lt;p&gt;If your data is super relational, Postgres usually wins. If your data is document-shaped, Mongo usually wins. A lot of real systems end up using both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why JSONB vs BSON Benchmarks Are Kinda Misleading
&lt;/h2&gt;

&lt;p&gt;You see a lot of benchmarks where someone compares Mongo documents against Postgres JSONB documents and concludes Mongo is faster. From this video: &lt;a href="https://www.youtube.com/watch?v=ZZ2tx8iL3P4" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=ZZ2tx8iL3P4&lt;/a&gt; (I am not the author of the video).&lt;/p&gt;

&lt;p&gt;And for that test, the numbers are probably right. But the conclusion people pull from them often isn't.&lt;/p&gt;

&lt;p&gt;There's two things going on with benchmarks like this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The data models aren't really comparable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JSONB isn't really Postgres's main data model. So when you benchmark Mongo documents against Postgres JSONB documents, what you're actually comparing is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A document database&lt;/li&gt;
&lt;li&gt;A relational database being used as a document database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A fairer Postgres benchmark would model the same data using normalized tables, foreign keys, real indexes, joins, the whole thing. A lot of workloads that suck in JSONB are actually really fast once you model them properly. The reverse is true too. Workloads that feel natural in Mongo get weird when you force them into rows and joins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The durability defaults aren't comparable either.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In that video specifically, Mongo was running with its default writeConcern, which only flushes the journal every 100ms. Postgres was running with its default WAL fsync on every commit. So Mongo gets to acknowledge writes faster, because it's literally promising less durability per write. That's not "Mongo is faster than SQL." That's "Mongo is faster when you let it relax its durability." Crank Mongo up to &lt;code&gt;j: true&lt;/code&gt; or &lt;code&gt;w: "majority"&lt;/code&gt; with proper sync and the gap closes a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Durability Isn't a Mongo Weakness Anymore
&lt;/h2&gt;

&lt;p&gt;Like I mentioned above, the "Mongo loses data" thing is mostly an artifact of how people ran Mongo in the early 2010s.&lt;/p&gt;

&lt;p&gt;Modern Mongo gives you journaling, replica sets, majority-acknowledged writes, multi-doc transactions, point-in-time recovery, and distributed replication.&lt;/p&gt;

&lt;p&gt;A write with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;writeConcern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;w&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;majority"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is durable across multiple replica set members before it even gets acknowledged.&lt;/p&gt;

&lt;p&gt;The actual durability gap between a properly configured Mongo cluster and a properly configured Postgres cluster is way smaller than people assume. Most "is it durable" arguments these days are really arguments about operational choices and consistency models, not about the storage engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Mongo Actually Wins
&lt;/h2&gt;

&lt;p&gt;There are real workloads where Mongo is just the better tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documents that get mutated a lot
&lt;/h3&gt;

&lt;p&gt;Mongo is great when you're updating documents constantly and each update only touches a small piece of the doc. Stuff like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Counters&lt;/li&gt;
&lt;li&gt;User state&lt;/li&gt;
&lt;li&gt;Device state&lt;/li&gt;
&lt;li&gt;Telemetry that gets enriched over time&lt;/li&gt;
&lt;li&gt;Session data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Postgres JSONB has to rewrite the whole JSONB value every time. Mongo often doesn't. This gap is huge in practice. Mongo can churn through partial updates at a rate that JSONB just can't match unless you pull the hot fields out into real columns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deeply nested data
&lt;/h3&gt;

&lt;p&gt;Mongo handles nested objects, arrays, and embedded docs naturally. You don't have to join your way through five tables to assemble a real object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Query patterns you can't predict yet
&lt;/h3&gt;

&lt;p&gt;If your users can add arbitrary fields and then query them later, Mongo's flexibility is hard to beat. You don't have to know the schema ahead of time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Horizontal write scaling
&lt;/h3&gt;

&lt;p&gt;Mongo's sharding was built into the database from the start. Postgres can scale out too, but you usually end up with partitioning, extensions, distributed variants, or app-level sharding. None of those feel as native as Mongo's sharding does. That's one of MongoDB's biggest strengths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document-centric workloads
&lt;/h3&gt;

&lt;p&gt;Mongo really shines when each request reads one doc, updates one doc, writes one doc. No joins, no fan-out, just the doc as the unit of work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Big documents that change a lot
&lt;/h3&gt;

&lt;p&gt;If your documents are large, mutated frequently, and accessed as a single unit, Mongo is basically designed for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Postgres Still Wins
&lt;/h2&gt;

&lt;p&gt;Mongo's good at a lot, but Postgres still owns a few areas pretty cleanly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complex joins
&lt;/h3&gt;

&lt;p&gt;Postgres's query planner is incredible. It's hard to overstate how good it is at joins. It actually outperforms MongoDB by a lot in a couple of public benchmarks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referential integrity
&lt;/h3&gt;

&lt;p&gt;Foreign keys actually enforce relationships. Mongo can't really do this natively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reporting / analytics
&lt;/h3&gt;

&lt;p&gt;SQL is still the language for analytics and BI. Pretty much every tool on the planet speaks it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Heavily relational data
&lt;/h3&gt;

&lt;p&gt;When your data is naturally graphy/relational, Postgres usually produces a cleaner design.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-row transactions
&lt;/h3&gt;

&lt;p&gt;Postgres's transaction model is one of its biggest strengths. Mongo has transactions too, but they're more limited.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Java vs Python Way of Thinking About It
&lt;/h2&gt;

&lt;p&gt;Here's an analogy that kind of clicks for me. You can almost think of SQL like Java and Mongo like Python.&lt;/p&gt;

&lt;p&gt;Java has built-in types, strict structure, classes everywhere. It kind of forces you to organize your code and keep things modular. You can't really get away with being sloppy, because the language won't let you. SQL is similar. Schemas, types, constraints, foreign keys. The structure is enforced for you whether you want it or not.&lt;/p&gt;

&lt;p&gt;Python is more like Mongo. Super flexible, super widely used, still really popular and not going anywhere. But if you don't have the self-discipline to make actual classes, structure your modules properly, and keep things organized, your codebase falls apart pretty fast. It's the same with Mongo. The flexibility is great until you stop enforcing schema at the app layer and your collections turn into a mess of inconsistent docs.&lt;/p&gt;

&lt;p&gt;Neither is bad. Python is huge, Mongo is huge. They give you a lot of room to move fast. But the room to move fast is also the room to shoot yourself in the foot. Java and SQL take that choice away from you, which sucks when you want flexibility and is great when you need guardrails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different Tools, Different Assumptions
&lt;/h2&gt;

&lt;p&gt;The way I think about it is that Postgres and Mongo aren't really competing for the same spot. They're built on different assumptions.&lt;/p&gt;

&lt;p&gt;Postgres assumes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relationships matter&lt;/li&gt;
&lt;li&gt;Consistency matters&lt;/li&gt;
&lt;li&gt;Joins matter&lt;/li&gt;
&lt;li&gt;Transactions matter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mongo assumes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documents are the unit of work&lt;/li&gt;
&lt;li&gt;Schema evolves&lt;/li&gt;
&lt;li&gt;Updates are localized&lt;/li&gt;
&lt;li&gt;Horizontal scaling matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither one is universally right. The mistake is forcing your workload into the wrong set of assumptions, and then being mad when the database fights you. The best database is usually just the one whose assumptions most closely match what your app actually does.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Note on Where This Is Coming From
&lt;/h2&gt;

&lt;p&gt;For context: I've been building a tool called &lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;VisuaLeaf &lt;/a&gt;for the last year and a half. It's a visual GUI for both MongoDB and PostgreSQL. Same workspace, same workflow, whichever database your data happens to live in. You can even migrate from sql databases to a mongodb database using VisuaLeafs Tasks/&lt;/p&gt;

&lt;p&gt;Building it means I spend a kind of unreasonable amount of time inside both engines. A lot of these misconceptions come up in support tickets, Reddit threads, and questions from people picking between the two, so I figured I'd dump them in one spot instead of typing the same reply over and over.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>postgres</category>
      <category>database</category>
      <category>software</category>
    </item>
    <item>
      <title>PostgreSQL JSONB vs MongoDB BSON: The Real Architectural Tradeoffs</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Wed, 08 Jul 2026 13:04:12 +0000</pubDate>
      <link>https://dev.to/visualeaf/postgresql-jsonb-vs-mongodb-bson-the-real-architectural-tradeoffs-4n8k</link>
      <guid>https://dev.to/visualeaf/postgresql-jsonb-vs-mongodb-bson-the-real-architectural-tradeoffs-4n8k</guid>
      <description>&lt;p&gt;Most teams pick between Postgres and Mongo by arguing about SQL vs documents, transactions, joins, or what everyone's using at the moment. The format on disk barely makes it into the discussion. That’s the wrong place to stop, because each database’s byte-level design carries the philosophy of the engine. BSON is a binary echo of MongoDB's runtime: a self-describing wire format that the server can scan, mutate, and ship easily. JSONB is a parse tree frozen into a Postgres tuple: optimized for read-time access, indifferent to write-time mutation, and beholden to MVCC.&lt;/p&gt;

&lt;p&gt;Once you know what each format actually is, the rest of the comparison stops being a religious argument and starts being a set of engineering tradeoffs you can reason about. This piece walks through what BSON and JSONB are at the byte level, how they behave once they hit storage, what each one costs to index, update, and read back, and which workloads each one quietly punishes.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu00kqt61872hhcwdsj46.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu00kqt61872hhcwdsj46.png" alt="mongodb bson vs postgres jsonb.png" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the format matters more than the API
&lt;/h2&gt;

&lt;p&gt;Application developers see JSON. Both engines accept JSON on the way in and serve JSON on the way out, so it is tempting to assume the storage format is a cosmetic detail. It is not. The storage format dictates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How much byte juggling the server does on every read.&lt;/li&gt;
&lt;li&gt;Whether a partial update can mutate a value in place or has to rewrite the entire document.&lt;/li&gt;
&lt;li&gt;What kinds of indexes can be built and how big they get.&lt;/li&gt;
&lt;li&gt;How much write amplification you pay when a single field changes.&lt;/li&gt;
&lt;li&gt;Whether the disk representation survives a torn page or a partial flush.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A query that runs in 1ms on a hot row can run in 30ms if the format forces the server to materialize and reparse the row. A field update that flips a boolean can rewrite 8KB of heap, generate WAL, trigger toast churn, and invalidate three indexes, or it can patch four bytes. The format decides which world you live in.&lt;/p&gt;

&lt;h2&gt;
  
  
  BSON: a binary echo of MongoDB's runtime
&lt;/h2&gt;

&lt;p&gt;BSON stands for Binary JSON. BSON is a length-prefixed, type-tagged, ordered key-value format that was designed with three properties in mind: cheap to parse linearly, cheap to mutate in place when the new value is the same size, and rich enough to carry types that JSON cannot express.&lt;/p&gt;

&lt;p&gt;The wire layout of a BSON document looks roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int32  total_document_length_in_bytes
{ element }*
byte   0x00  // terminator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each element is itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;byte    type_tag    (0x01 double, 0x02 string, 0x03 embedded doc, 0x07 ObjectId, ...)
cstring field_name
&amp;lt;payload depending on type&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things follow from that layout. First, every document and every embedded subdocument carries its own length prefix, which means a parser can skip an entire subtree in one pointer arithmetic step. Second, fields are ordered. The same logical document can be encoded in different byte sequences depending on insertion order, and the server preserves that order.&lt;/p&gt;

&lt;p&gt;The type tag set is wider than JSON's. BSON has dedicated tags for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;32 bit and 64 bit integers (JSON has only a generic number).&lt;/li&gt;
&lt;li&gt;IEEE 754 decimal128 for financial workloads.&lt;/li&gt;
&lt;li&gt;ObjectId (12 bytes: timestamp, machine id, counter).&lt;/li&gt;
&lt;li&gt;UTC datetime (int64 milliseconds since epoch).&lt;/li&gt;
&lt;li&gt;Binary blobs with a subtype byte.&lt;/li&gt;
&lt;li&gt;UUID (a binary subtype).&lt;/li&gt;
&lt;li&gt;Regular expressions.&lt;/li&gt;
&lt;li&gt;A JavaScript code type, mostly historical.&lt;/li&gt;
&lt;li&gt;MinKey and MaxKey sentinels used for index bounds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two consequences for engineers. One: BSON round trips numeric types faithfully. A column that stores 64 bit account ids does not silently become a double the way it would in pure JSON. Two: BSON carries metadata that JSON cannot, which is part of the reason a MongoDB driver feels chatty when you push it through a strict JSON pipeline.&lt;/p&gt;

&lt;p&gt;The clever bit, and the one that distinguishes BSON from a hundred other binary JSON formats: every field's payload is preceded by enough information that a server can walk the document linearly without recursive parsing, and many field updates can be performed by patching the payload in place. If you change an int32 field from 7 to 8, the document length does not change, the field offset does not move, and the engine writes four bytes. That property is what lets WiredTiger keep update latency flat across a wide range of document sizes.&lt;/p&gt;

&lt;p&gt;It also explains the cost of BSON. Field names are stored as raw cstrings in every document. A collection of a billion documents with a &lt;code&gt;created_at&lt;/code&gt; field carries the literal bytes &lt;code&gt;created_at\0&lt;/code&gt; a billion times. There is no schema, no dictionary, no shared symbol table. Wide documents with long field names waste a lot of disk and a lot of memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSONB: a parse tree frozen on disk
&lt;/h2&gt;

&lt;p&gt;JSONB is the spiritual opposite of BSON. Where BSON is a wire format that happens to live on disk, JSONB is a storage format that happens to be transferable. Postgres parses incoming JSON, normalizes it (keys sorted, whitespace stripped, duplicate keys deduplicated with last write wins), and serializes the result into a binary structure that maps directly onto the engine's value tree.&lt;/p&gt;

&lt;p&gt;There is no public byte spec the way there is for BSON. Internally, a JSONB value is a header plus a sequence of entries that describe each key value pair, plus the data area. The headers contain length and type bits so the engine can binary search keys inside an object, and offsets are stored every N entries to bound the cost of finding a specific key. That structure has two big implications.&lt;/p&gt;

&lt;p&gt;First, JSONB is a read optimized format. Once the document is stored, looking up a key by name is logarithmic in the number of keys, not linear. For wide objects with hundreds of fields, this matters. BSON, by contrast, is linear: it walks the document until it finds the key, leveraging the length prefixes to skip subtrees.&lt;/p&gt;

&lt;p&gt;Second, JSONB cannot be patched in place. The header layout, the offset cache, and the dedup pass all assume the value is being constructed from scratch. Updating a single boolean inside a 4KB JSONB document materializes a brand new 4KB JSONB document, writes a new heap tuple, marks the old one dead, and updates every index that references it. This is not a JSONB design flaw, it is the consequence of binding the format to Postgres's MVCC and TOAST machinery. JSONB does what makes Postgres fast at reads. Postgres pays for the rest at write time.&lt;/p&gt;

&lt;p&gt;JSONB throws away two things compared to JSON. Key order is lost (objects are stored with keys sorted), and duplicate keys are collapsed. Most applications never notice, but if you are relying on either property, you want &lt;code&gt;json&lt;/code&gt; (the text type) not &lt;code&gt;jsonb&lt;/code&gt;. Almost nobody should be relying on either property.&lt;/p&gt;

&lt;p&gt;JSONB also does not preserve numeric type fidelity in the same way BSON does. Postgres has its own &lt;code&gt;numeric&lt;/code&gt; type which is arbitrary precision, and JSONB encodes numbers using that representation. You will not lose precision the way you would with a 64 bit float, but you also do not get a distinct int32 vs int64 tag the way BSON gives you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Binary blobs and where the type systems leak
&lt;/h2&gt;

&lt;p&gt;The gap between BSON and JSONB shows up the fastest when data falls outside JSON's native type system.&lt;/p&gt;

&lt;p&gt;Binary blobs are the usual offender. BSON has a native binary type with a subtype tag, JSONB does not. In Postgres your options are base64 encoding the bytes into JSONB (ugly), or pulling them out into a separate &lt;code&gt;bytea&lt;/code&gt; column and referencing them by id (cleaner). Splitting the document works fine when you own the schema, it becomes awkward when you are ingesting third party documents that already embed binary fields, like S3 events with attachments or message payloads with thumbnails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storage: WiredTiger pages vs heap tuples plus TOAST
&lt;/h2&gt;

&lt;p&gt;The byte format is half the story. The other half is what the storage engine does with the bytes.&lt;/p&gt;

&lt;p&gt;MongoDB stores BSON documents inside WiredTiger, a B+ tree storage engine that also backs a number of other databases. WiredTiger gives MongoDB two important properties:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Block compression by default.&lt;/strong&gt; Snappy compresses each block; zstd is available and can roughly halve the disk footprint on text heavy collections. The compression happens at the storage layer, so the in memory representation is uncompressed but the on disk and on wire (replication) footprint is much smaller. For a workload that stores web event payloads or product catalogs, the ratio of on disk size to logical size is routinely 3:1 or better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In place updates when possible.&lt;/strong&gt; If a field changes and the new BSON encoding fits in the existing slot, WiredTiger patches the page. If the document grows beyond its allocated space, WiredTiger rewrites the document, which is the expensive path. Schema decisions matter here: documents with arrays that grow over time will rewrite often, and the standard advice is to size arrays carefully or break them out into separate collections.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;WiredTiger maintains a journal (write ahead log) that commits to disk every 100ms by default, and snapshots dirty pages to disk at 60 second checkpoints. The two intervals together keep recovery time bounded without grinding the write path on every commit.&lt;/p&gt;

&lt;p&gt;PostgreSQL stores JSONB inside a heap tuple, the same structure that holds every other Postgres row. The heap is a page based store (8KB pages by default) with row level MVCC. Every update writes a new tuple, links it to the old one, and lets autovacuum reclaim the dead copy later.&lt;/p&gt;

&lt;p&gt;JSONB also interacts with TOAST (The Oversized Attribute Storage Technique). Any column value that exceeds approximately 2KB after compression gets pushed into a separate TOAST table and replaced in the main heap with a pointer. JSONB documents larger than that threshold therefore live in two places: the heap tuple holds a pointer, and the actual JSONB lives in toast chunks. Reading the document means following the pointer and reassembling the chunks. The default TOAST strategy for &lt;code&gt;jsonb&lt;/code&gt; is &lt;code&gt;EXTENDED&lt;/code&gt;, which means values are first compressed (using the cluster's default compression, pglz or lz4 since PG 14), and then chunked if still over threshold.&lt;/p&gt;

&lt;p&gt;The two consequences are easy to miss:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;SELECT *&lt;/code&gt; on a table with TOASTed JSONB columns will fetch the entire chain even if you only wanted three scalar fields from the row. Project the columns you need or extract the JSONB fields explicitly.&lt;/li&gt;
&lt;li&gt;Updating one field in a JSONB document materializes a new JSONB, which gets TOASTed again. The old TOAST chunks become dead and wait for autovacuum. On a heavy update workload against large JSONB documents, the TOAST table can balloon faster than the main heap.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Postgres 14 added LZ4 compression for TOAST, which is meaningfully faster than the legacy pglz both for compression and decompression. If your JSONB columns are large and updated often, switching to LZ4 is the single highest leverage TOAST change you can make.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updates: in place vs MVCC tombstones
&lt;/h2&gt;

&lt;p&gt;Spend ten minutes profiling a heavy update workload on each engine and the contrast jumps out.&lt;/p&gt;

&lt;p&gt;In MongoDB, a field level update with &lt;code&gt;$set&lt;/code&gt;, &lt;code&gt;$inc&lt;/code&gt;, or &lt;code&gt;$push&lt;/code&gt; is interpreted by the server and translated into a targeted mutation of the BSON document. If the new value fits, WiredTiger updates the page in place. If it does not fit, the document is rewritten. Index entries are only touched for the fields that actually changed and that are indexed. The journal records the delta, not the whole document.&lt;/p&gt;

&lt;p&gt;In PostgreSQL, &lt;code&gt;UPDATE&lt;/code&gt; on a JSONB column always rewrites the entire JSONB value. The &lt;code&gt;jsonb_set&lt;/code&gt; function looks surgical at the SQL layer (it lets you set a specific path) but underneath, it builds a new JSONB and the row update replaces the old tuple. MVCC then leaves a dead tuple behind, autovacuum reclaims it later, and every index on the table that does not satisfy the HOT (Heap Only Tuple) conditions has to insert a new entry pointing at the new tuple. If your indexes reference fields inside the JSONB column, HOT is off the table and every update is amplified.&lt;/p&gt;

&lt;p&gt;In practice this means two patterns dominate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MongoDB rewards documents with mutable internals.&lt;/strong&gt; A counter inside a document, a status field that flips often, an array that gets pushed to on every event: these are cheap operations. The flip side is that document growth is the silent killer. A document that starts at 1KB and grows to 50KB over a year is rewritten by WiredTiger every time it crosses its current allocation, which means the late life updates are dramatically more expensive than the early life updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PostgreSQL rewards documents that are read more than they are updated.&lt;/strong&gt; Catalog data, feature flags, event payloads that are written once and read many times, configuration that changes weekly rather than per second: JSONB is excellent for these. The moment you start treating a JSONB document as a per row mutable object that changes on every request, you are fighting the engine.&lt;/p&gt;

&lt;p&gt;The benchmark that exposes this gap is straightforward. Take a million row table or collection, each row holding a 4KB document with a &lt;code&gt;view_count&lt;/code&gt; integer somewhere inside it. Increment the counter once per second per row across all rows. MongoDB may only need to modify the bytes associated with the changed field, avoiding the full document rewrite that JSONB incurs. Postgres rewrites 4KB of JSONB per document, generates 4KB of WAL per update, and starts producing dead tuples faster than autovacuum can clean them. The Postgres answer here is simple: do not store &lt;code&gt;view_count&lt;/code&gt; in JSONB. Pull it into a regular &lt;code&gt;bigint&lt;/code&gt; column. That fix is real and lasting, and it is also a tax on schemas that try to be JSON first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indexes: GIN, multikey, and what each can answer
&lt;/h2&gt;

&lt;p&gt;Both engines let you index inside documents. The mechanisms are different, and the resulting indexes have different shapes.&lt;/p&gt;

&lt;p&gt;PostgreSQL offers two index strategies for JSONB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GIN indexes on the whole document.&lt;/strong&gt; The default operator class supports containment (&lt;code&gt;@&amp;gt;&lt;/code&gt;), key existence, and path queries. A more aggressive variant, &lt;code&gt;jsonb_path_ops&lt;/code&gt;, supports only &lt;code&gt;@&amp;gt;&lt;/code&gt; but produces a smaller, faster index. Both are inverted indexes that emit one entry per path through the document.&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;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_events_data&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;GIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="n"&gt;jsonb_path_ops&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="o"&gt;@&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'{"type": "signup"}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;B tree indexes on specific expressions.&lt;/strong&gt; When you know the exact path you want to query, an expression B tree is dramatically smaller and faster.&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;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_events_user_id&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'12345'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MongoDB indexes work on field paths directly. The standard &lt;code&gt;createIndex({user_id: 1, created_at: -1})&lt;/code&gt; builds a B tree on a compound path. The syntax is different from Postgres, but the behavior is familiar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multikey indexes.&lt;/strong&gt; When the indexed field is an array, MongoDB automatically creates one index entry per array element. The same B tree, traversed differently. A document with &lt;code&gt;tags: ["postgres", "mongodb", "bson"]&lt;/code&gt; generates three index entries pointing at the same document, and any element match query can use the index. This is the killer feature for tags, references, and other array shaped data.&lt;/p&gt;

&lt;p&gt;For fixed, known query shapes, Postgres ties or beats Mongo with expression B trees. For varied or array heavy data, Mongo's first class multikey support gives it more leverage with less ceremony.&lt;/p&gt;

&lt;p&gt;One more thing Postgres has on Mongo here: partial indexes with arbitrary predicates. You can build an index that only covers the rows where some JSONB field has a specific value, or a date range, or whatever. Mongo has partial indexes too but the filter expressions you can use are way more limited, so anything more than a simple equality check usually has to live in the query side instead of the index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read paths and the cost of materialization
&lt;/h2&gt;

&lt;p&gt;The end to end read path is where the two formats earn or lose their reputation.&lt;/p&gt;

&lt;p&gt;A MongoDB find that hits an index and returns a single document does roughly the following: traverse the B tree to find the record id, fetch the page from WiredTiger, decompress the block, locate the BSON document inside the page, copy it into the response buffer, ship it over the wire. The document is already in BSON. If the driver supports it (most do), the bytes can travel from the storage page to the client with no parse on the server side. Field projection (&lt;code&gt;$project&lt;/code&gt; in aggregation, or projection on &lt;code&gt;find&lt;/code&gt;) walks the BSON in place and emits a trimmed version.&lt;/p&gt;

&lt;p&gt;A PostgreSQL select that hits an index and returns a single row does roughly the following: traverse the B tree to find the heap tuple location, check the visibility map and the tuple's xmin/xmax to confirm the row is visible to this transaction, fetch the heap page, locate the tuple, follow any TOAST pointers to reassemble JSONB columns, materialize the row into the executor's tuple format, apply any projections, and emit. The visibility check is the MVCC tax. The TOAST chase is the wide column tax. The materialization is the format tax.&lt;/p&gt;

&lt;p&gt;For point reads of small documents, both engines are fast and the differences are noise. For wide documents (tens of KB) or selective projections on a large document, BSON has a structural edge because the on disk format and the on wire format are the same, and projection is a walk. JSONB has to be unpacked and the projection produces new JSONB. The win is not huge in absolute terms, but it shows up on workloads that fan out reads.&lt;/p&gt;

&lt;p&gt;Aggregations flip it though. Postgres has been working on its query planner for like 30 years. Parallel scans, hash joins, merge joins, a cost based optimizer that has seen basically every shape of analytical query a person can write. Mongo's aggregation pipeline has gotten way better in recent versions (SBE is faster, &lt;code&gt;$lookup&lt;/code&gt; is actually usable now), but once you're doing real analytics with multiple joins and big group by aggregates, Postgres just wins. Not by a small margin either, you'll often see big multiples on the same workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  When PostgreSQL JSONB is the right answer
&lt;/h2&gt;

&lt;p&gt;Reach for JSONB when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The bulk of your schema is relational and a few columns happen to be semi structured. Customer records with a metadata field. Products with a variable attributes blob. Orders with line items that have inconsistent shape across categories.&lt;/li&gt;
&lt;li&gt;Reads dominate writes against the JSONB columns. Catalog data, configuration, audit payloads, settings.&lt;/li&gt;
&lt;li&gt;You need joins. Postgres can join JSONB columns against regular columns against full text indexes against PostGIS geometries against time series partitions in one query. Mongo can do this through &lt;code&gt;$lookup&lt;/code&gt; but it is not the same.&lt;/li&gt;
&lt;li&gt;You need transactions across many rows. JSONB inherits Postgres's transaction model for free.&lt;/li&gt;
&lt;li&gt;The team is already running Postgres and the operational cost of adding a second database is not justified.&lt;/li&gt;
&lt;li&gt;You want strong typing in some columns and document flexibility in others, in the same table.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Workloads that fit this shape: SaaS application data, e commerce catalogs, CMS storage, configuration stores, audit logs that need to be queried by structured fields, anything where the analytical query layer is going to use SQL anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  When MongoDB BSON is the right answer
&lt;/h2&gt;

&lt;p&gt;Reach for MongoDB when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The unit of work is the document. Each request reads or writes one document, occasionally a few. Most operations do not span documents.&lt;/li&gt;
&lt;li&gt;Documents are large, mutate frequently, and the mutations are field local. Telemetry events that get enriched over time. Game state. IoT device shadows. Anything where the same document gets touched many times and each touch is small.&lt;/li&gt;
&lt;li&gt;The query patterns are varied and the schema is genuinely fluid. You do not know which fields users will query next month.&lt;/li&gt;
&lt;li&gt;You need horizontal write scaling out of the box. Mongo's native sharding has gotten very good. Postgres has sharding solutions (Citus, partitioning) but they are bolted on rather than first class.&lt;/li&gt;
&lt;li&gt;You need a document oriented secondary index pattern that Postgres expression indexes cannot model cleanly.&lt;/li&gt;
&lt;li&gt;The team has Mongo expertise and the workload does not need SQL analytics.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Workloads that fit this shape: real time event streams with rich payloads, mobile and game backends, IoT device fleets, content management with deeply nested structures, anything where the data model is naturally a graph of nested objects and the queries are mostly key value style with occasional secondary lookups.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical takeaway
&lt;/h2&gt;

&lt;p&gt;If you remember three things from this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The format is the engine.&lt;/strong&gt; BSON is what makes Mongo fast at field updates and fast at projection. JSONB is what makes Postgres flexible without giving up relational performance. The choice between them is not about JSON vs binary, it is about update behavior, index shape, and read path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSONB is a read optimized format.&lt;/strong&gt; It pays for itself when you write once and read many. It punishes you when you treat a JSONB column as a mutable object that changes on every request. Pull hot mutable fields out into regular columns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BSON is an update optimized format.&lt;/strong&gt; It pays for itself when documents are touched often and the touches are local. It punishes you when documents grow unboundedly, when field names are long, and when the query pattern wants joins and aggregations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pick the engine whose architectural assumptions match your workload's access pattern. Everything else is a tax you will pay every day until you fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with MongoDB documents?
&lt;/h2&gt;

&lt;p&gt;Understanding BSON is useful, but seeing the structure of your collections makes the work much easier.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt;, you can browse MongoDB documents, inspect schemas visually, build queries, create aggregation pipelines, and understand how your data is actually organized.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>postgres</category>
      <category>database</category>
      <category>software</category>
    </item>
    <item>
      <title>MongoDB Workspace for Queries, Schema, Charts, and Teams</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Mon, 06 Jul 2026 08:51:06 +0000</pubDate>
      <link>https://dev.to/visualeaf/mongodb-workspace-for-queries-schema-charts-and-teams-373l</link>
      <guid>https://dev.to/visualeaf/mongodb-workspace-for-queries-schema-charts-and-teams-373l</guid>
      <description>&lt;p&gt;MongoDB work is rarely just one task.&lt;/p&gt;

&lt;p&gt;You may start by browsing a collection, but soon you need to build a query, test an aggregation, check the schema, create a chart, inspect indexes, compare data, or explain the database to someone else.&lt;/p&gt;

&lt;p&gt;That is why &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt; is built as a visual MongoDB workspace.&lt;/p&gt;

&lt;p&gt;Instead of keeping queries, aggregations, schema diagrams, dashboards, performance checks, and screenshots in separate places, VisuaLeaf brings the main MongoDB workflows closer together in one interface.&lt;/p&gt;

&lt;p&gt;It is made for developers and teams who want to work visually, but still keep access to the generated MongoDB code when they need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manage MongoDB connections in one place
&lt;/h2&gt;

&lt;p&gt;Most teams work with more than one MongoDB connection.&lt;/p&gt;

&lt;p&gt;You may have a local database, an &lt;a href="https://www.mongodb.com/products/platform/atlas-database" rel="noopener noreferrer"&gt;Atlas cluster&lt;/a&gt;, a staging environment, and production.&lt;/p&gt;

&lt;p&gt;VisuaLeaf’s &lt;a href="https://visualeaf.com/features/connection-manager/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Connection Manager&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; helps you organize and open your MongoDB connections from one workspace.&lt;/p&gt;

&lt;p&gt;This is useful when you switch between projects, compare environments, or need quick access to the databases you use every day.&lt;/p&gt;

&lt;p&gt;Instead of starting from zero every time, your MongoDB workspace starts with the connections you already work 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1gyon3iwt0fgtaa4g8nj.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1gyon3iwt0fgtaa4g8nj.webp" alt="VisuaLeaf Connection Manager showing MongoDB connections inside the workspace" width="799" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Manage local, Atlas, staging, and production MongoDB connections from one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browse MongoDB collections in different views
&lt;/h2&gt;

&lt;p&gt;The first job of any MongoDB tool is simple: help you see the data clearly.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can &lt;a href="https://visualeaf.com/features/browse-collections/" rel="noopener noreferrer"&gt;browse collections&lt;/a&gt; in different views, depending on what you need.&lt;/p&gt;

&lt;p&gt;Use *&lt;strong&gt;&lt;em&gt;Tree View&lt;/em&gt;&lt;/strong&gt;* when the documents are nested, and you want to open fields step by step.&lt;/p&gt;

&lt;p&gt;Use *&lt;strong&gt;&lt;em&gt;Table View&lt;/em&gt;&lt;/strong&gt;* when you want to scan many documents quickly.&lt;/p&gt;

&lt;p&gt;Use *&lt;strong&gt;&lt;em&gt;JSON or BSON View&lt;/em&gt;&lt;/strong&gt;* when you need to inspect the raw document structure.&lt;/p&gt;

&lt;p&gt;This is useful when you are debugging real data, checking nested fields, reviewing documents, or explaining a collection to someone else.&lt;/p&gt;

&lt;p&gt;You can also insert, edit, and delete documents from the same workspace, so basic data work does not become slower than it needs to be.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4z1cvt9gfwcfcs2o5evd.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4z1cvt9gfwcfcs2o5evd.png" alt="VisuaLeaf MongoDB collection browser showing documents in tree, table, JSON, and BSON views" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Browse MongoDB collections in the view that fits the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build MongoDB queries visually
&lt;/h2&gt;

&lt;p&gt;Writing MongoDB queries manually is useful. But when a query has multiple filters, nested fields, sorting, projection, and limits, it is easy to make small mistakes.&lt;/p&gt;

&lt;p&gt;VisuaLeaf’s &lt;a href="https://visualeaf.com/features/visual-query-builder/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Visual Query Builder&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; helps you build the query step by step.&lt;/p&gt;

&lt;p&gt;You choose the field, operator, and value. Then you add sorting, projection, and limit if you need them.&lt;/p&gt;

&lt;p&gt;The important part is that you still see the generated MongoDB query.&lt;/p&gt;

&lt;p&gt;So you are not locked into a visual interface. You can build visually, test the result, and copy or review the code whenever you need it.&lt;/p&gt;

&lt;p&gt;This is helpful for juniors, onboarding, debugging filters, or showing a teammate why a query returns certain 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F09xtk7jrcg3u9pczkd19.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F09xtk7jrcg3u9pczkd19.webp" alt="VisuaLeaf visual MongoDB query builder with filters, sorting, projection, limit, and generated query" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build MongoDB queries visually and keep the generated code visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test aggregation pipelines stage by stage
&lt;/h2&gt;

&lt;p&gt;Aggregation pipelines can become hard to read fast.&lt;/p&gt;

&lt;p&gt;One &lt;code&gt;$match&lt;/code&gt; is fine. A &lt;code&gt;$group&lt;/code&gt; is fine. But after &lt;code&gt;$lookup&lt;/code&gt;, &lt;code&gt;$unwind&lt;/code&gt;, &lt;code&gt;$project&lt;/code&gt;, &lt;code&gt;$sort&lt;/code&gt;, and more stages, it can be hard to know where the result changed.&lt;/p&gt;

&lt;p&gt;VisuaLeaf’s &lt;a href="https://visualeaf.com/features/aggregation-pipeline/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Aggregation Pipeline Builder&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; lets you build pipelines one stage at a time.&lt;/p&gt;

&lt;p&gt;You can see the input, add a stage, check the output, and continue from there.&lt;/p&gt;

&lt;p&gt;This makes the pipeline easier to debug because you do not have to wait until the final result to notice something is wrong.&lt;/p&gt;

&lt;p&gt;It also makes aggregations easier to explain during teamwork, because each stage has a clear role.&lt;/p&gt;

&lt;p&gt;You still get the generated aggregation code, so the visual builder helps you understand the pipeline instead of hiding 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6h8ecq24bvrcyzrxpohv.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6h8ecq24bvrcyzrxpohv.webp" alt="VisuaLeaf MongoDB aggregation pipeline builder with stage-by-stage input and output preview" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build and debug MongoDB aggregations stage by stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use *&lt;strong&gt;&lt;em&gt;AI Assistant&lt;/em&gt;&lt;/strong&gt;* when you need a faster starting point
&lt;/h2&gt;

&lt;p&gt;Sometimes you know what you want from the data, but you do not want to start from zero.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can use &lt;a href="https://visualeaf.com/features/ai-helper/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;AI Assistant&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; while working with the &lt;a href="https://visualeaf.com/blog/build-mongodb-queries-visually/" rel="noopener noreferrer"&gt;Visual Query Builder&lt;/a&gt; or the &lt;a href="https://visualeaf.com/blog/mongodb-aggregation-pipeline-explained-with-examples/" rel="noopener noreferrer"&gt;Aggregation Pipeline Builder.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can help generate a first query or pipeline from your prompt. Then you can review the result, test it with your data, adjust it visually, and keep the generated MongoDB code visible.&lt;/p&gt;

&lt;p&gt;AI Assistant gives you a faster starting point, but you still stay in control of the final result.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffr5qy0jb83yq30qy7b8u.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffr5qy0jb83yq30qy7b8u.webp" alt="VisuaLeaf AI Assistant generating a MongoDB aggregation pipeline inside the visual pipeline builder." width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use AI to generate a first aggregation pipeline, then review and edit each stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand NoSQL schemas with diagrams
&lt;/h2&gt;

&lt;p&gt;MongoDB is flexible, but flexible does not mean structure does not exist.&lt;/p&gt;

&lt;p&gt;The structure is still there. It is inside the documents.&lt;/p&gt;

&lt;p&gt;You may have required fields, optional fields, nested objects, arrays, embedded documents, and references between collections.&lt;/p&gt;

&lt;p&gt;VisuaLeaf’s &lt;a href="https://visualeaf.com/features/visual-schema/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Schema Designer&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; helps you see that structure visually.&lt;/p&gt;

&lt;p&gt;This is useful when you join a new project, prepare documentation, explain the database to another developer, or try to understand how collections are connected.&lt;/p&gt;

&lt;p&gt;A schema diagram can make a MongoDB database easier to understand than reading documents one by one.&lt;/p&gt;

&lt;p&gt;This is especially helpful for teams, because not everyone has the same database knowledge in their head.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzqkzweb3fnfxqhxqyo4w.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzqkzweb3fnfxqhxqyo4w.png" alt="VisuaLeaf MongoDB schema diagram showing collections, fields, embedded documents, and references" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visual schema diagrams make flexible NoSQL data easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use JSON Schema Validation when you need to enforce structure
&lt;/h2&gt;

&lt;p&gt;MongoDB is flexible by default, but some collections need stricter rules.&lt;/p&gt;

&lt;p&gt;For example, you may want to require important fields, accept only specific data types, or make sure documents follow the same structure before they are inserted.&lt;/p&gt;

&lt;p&gt;VisuaLeaf’s &lt;a href="https://visualeaf.com/features/schema-validation/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;JSON Schema Validation&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; helps you define MongoDB validation rules visually.&lt;/p&gt;

&lt;p&gt;You can enforce structure where it matters, prevent bad data, and still see the generated JSON Schema validation code.&lt;/p&gt;

&lt;p&gt;This is useful when a collection is used by a team, an app, or any workflow where inconsistent data can create problems later.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fane1brpyl5e5bjtzm5t5.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fane1brpyl5e5bjtzm5t5.webp" alt="VisuaLeaf MongoDB JSON Schema designer for creating validation rules visually" width="799" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create MongoDB validation rules visually and keep the generated JSON Schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create charts and dashboards from MongoDB data
&lt;/h2&gt;

&lt;p&gt;Some MongoDB data is easier to understand visually.&lt;/p&gt;

&lt;p&gt;With VisuaLeaf’s &lt;a href="https://visualeaf.com/features/chart-builder/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Chart &amp;amp;&lt;/em&gt;&lt;/strong&gt;* *&lt;strong&gt;&lt;em&gt;Dashboard Builder&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt;, you can turn collection data into charts and group multiple views in one dashboard.&lt;/p&gt;

&lt;p&gt;This is useful for payments by status, orders by month, users by plan, expenses by category, or any data you want to understand faster.&lt;/p&gt;

&lt;p&gt;Charts and dashboards help you prepare demos, create quick internal reports, check product data, or explain results to people who do not want to read raw JSON documents.&lt;/p&gt;

&lt;p&gt;You can keep the visual data close to the collections, queries, and aggregations you are already 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsuvca1vz1sshmjrwy72n.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsuvca1vz1sshmjrwy72n.png" alt="VisuaLeaf MongoDB chart and dashboard builder showing visual charts created from collection data." width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create charts and dashboards from real MongoDB data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check query performance with Explain and Profiler
&lt;/h2&gt;

&lt;p&gt;When a MongoDB query is slow, you need more than a guess.&lt;/p&gt;

&lt;p&gt;You need to know if MongoDB is using an index, scanning too many documents, or doing a collection scan.&lt;/p&gt;

&lt;p&gt;VisuaLeaf includes tools like &lt;a href="https://visualeaf.com/blog/mongodb-query-optimization-indexes/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Explain Plan&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; and &lt;a href="https://visualeaf.com/features/query-profiler/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Query Profiler&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; to help you understand what happens behind a query.&lt;/p&gt;

&lt;p&gt;You can check execution details, scanned documents, returned documents, and index usage closer to the query itself.&lt;/p&gt;

&lt;p&gt;This makes performance work easier because you do not have to separate query building from query debugging.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fazhryejzej1dx378mk8i.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fazhryejzej1dx378mk8i.webp" alt="VisuaLeaf MongoDB query profiler showing execution details, scanned documents, and index usage" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check how MongoDB runs your query and find performance problems faster&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate MongoDB tasks with Task Manager
&lt;/h2&gt;

&lt;p&gt;Some MongoDB work does not need to be done manually every time.&lt;/p&gt;

&lt;p&gt;With VisuaLeaf’s &lt;a href="https://visualeaf.com/features/task-manager/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Task Manager&lt;/em&gt;&lt;/strong&gt;*,&lt;/a&gt; you can create and run tasks directly from the workspace.&lt;/p&gt;

&lt;p&gt;This is useful for repeated actions like running scripts, exporting data, syncing workflows, or handling MongoDB operations that you do not want to rebuild from zero each time.&lt;/p&gt;

&lt;p&gt;Instead of keeping these tasks in different places, you can manage them closer to the collections, queries, and tools you already use.&lt;/p&gt;

&lt;p&gt;For teams, this makes repeated MongoDB work easier to organize, run, and review.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn3u312jitfmsc4q20u8w.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn3u312jitfmsc4q20u8w.webp" alt="VisuaLeaf MongoDB Task Manager showing automated tasks inside the workspace." width="799" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use Task Manager to organize and run repeated MongoDB workflows from one place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compare collections across environments
&lt;/h2&gt;

&lt;p&gt;Local, staging, and production data do not always match.&lt;/p&gt;

&lt;p&gt;A document may be missing. A field may be different. A test collection may be outdated. And checking everything manually is slow.&lt;/p&gt;

&lt;p&gt;VisuaLeaf’s &lt;a href="https://visualeaf.com/features/collection-compare/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Collection Compare&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; helps you compare MongoDB collections and see the differences clearly.&lt;/p&gt;

&lt;p&gt;You can inspect missing documents, modified documents, and differences between collections before deciding what to fix or sync.&lt;/p&gt;

&lt;p&gt;This is useful for developers, QA work, migration checks, and teams working with multiple MongoDB environments.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fijbiz8mdhzggwwush7fj.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fijbiz8mdhzggwwush7fj.webp" alt="VisuaLeaf MongoDB collection compare showing missing and modified documents between environments" width="799" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compare MongoDB collections across local, staging, and production environments&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Mongo Shell when you need direct control
&lt;/h2&gt;

&lt;p&gt;Visual tools are helpful, but sometimes the shell is still the fastest option.&lt;/p&gt;

&lt;p&gt;VisuaLeaf includes a &lt;a href="https://visualeaf.com/features/mongo-shell/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;Mongo Shell with autocomplete&lt;/em&gt;&lt;/strong&gt;*,&lt;/a&gt; syntax highlighting, and visual results so that you can run commands directly inside the workspace.&lt;/p&gt;

&lt;p&gt;This keeps the workflow flexible.&lt;/p&gt;

&lt;p&gt;You can build visually when it saves time, or use the shell when a command gives you more direct control.&lt;/p&gt;

&lt;p&gt;The result is still easy to read, because you are not just writing commands in a plain terminal. You can run MongoDB commands and inspect the output visually in the same place.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1629sz2ckdtn80zlo9bt.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1629sz2ckdtn80zlo9bt.webp" alt="VisuaLeaf Mongo Shell with autocomplete, syntax highlighting, and visual results inside the MongoDB workspace." width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run MongoDB commands with autocomplete, syntax highlighting, and visual results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query MongoDB with SQL Mode
&lt;/h2&gt;

&lt;p&gt;Not every developer thinks in MongoDB syntax first.&lt;/p&gt;

&lt;p&gt;Some teams also have developers who come from SQL databases, or people who simply find SQL easier for quick exploration.&lt;/p&gt;

&lt;p&gt;VisuaLeaf includes &lt;a href="https://visualeaf.com/features/sql-mode/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;SQL Mode&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt;, so you can work with MongoDB data using a SQL-style query workflow.&lt;/p&gt;

&lt;p&gt;This can help when you want to explore collections faster, explain data to someone with a relational database background, or move between SQL and MongoDB work without changing tools.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc6dgulbbvev2dg6ih2dr.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc6dgulbbvev2dg6ih2dr.webp" alt="VisuaLeaf SQL Mode for querying MongoDB data with a SQL-style workflow" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use SQL Mode when a SQL-style workflow makes MongoDB data easier to explore.&lt;/p&gt;

&lt;h2&gt;
  
  
  View files stored in GridFS
&lt;/h2&gt;

&lt;p&gt;MongoDB is not always only documents.&lt;/p&gt;

&lt;p&gt;Some projects also store files using GridFS.&lt;/p&gt;

&lt;p&gt;VisuaLeaf includes a &lt;a href="https://visualeaf.com/features/gridfs-viewer/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;GridFS Viewer&lt;/em&gt;&lt;/strong&gt;*,&lt;/a&gt; so you can inspect files and file metadata from the same MongoDB workspace.&lt;/p&gt;

&lt;p&gt;This is useful when your application stores images, documents, uploads, or other large files in MongoDB.&lt;/p&gt;

&lt;p&gt;Instead of checking file data separately, you can keep it close to the collections and database structure you are already using.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft3j453a32fusvt3ko4ed.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft3j453a32fusvt3ko4ed.webp" alt="VisuaLeaf GridFS Viewer showing files stored in MongoDB GridFS" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;View files and metadata stored in MongoDB GridFS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review users and roles with RBAC Dashboard
&lt;/h2&gt;

&lt;p&gt;For teams, MongoDB access is not only about connecting to the database.&lt;/p&gt;

&lt;p&gt;You also need to understand who has access, which roles exist, and what permissions are assigned.&lt;/p&gt;

&lt;p&gt;VisuaLeaf’s &lt;a href="https://visualeaf.com/features/rbac-dashboard/" rel="noopener noreferrer"&gt;*&lt;strong&gt;&lt;em&gt;RBAC Dashboard&lt;/em&gt;&lt;/strong&gt;*&lt;/a&gt; helps you review MongoDB users, roles, and permissions in a clearer way.&lt;/p&gt;

&lt;p&gt;This is useful for team databases, shared environments, and projects where access control needs to be checked without digging through everything 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feqfptu1odi7xrwmna2lt.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feqfptu1odi7xrwmna2lt.webp" alt="VisuaLeaf RBAC Dashboard showing MongoDB users, roles, and permissions" width="799" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Review MongoDB users, roles, and permissions from the RBAC Dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick feature summary
&lt;/h2&gt;

&lt;p&gt;Replace the long final list with this:&lt;/p&gt;

&lt;h2&gt;
  
  
  Work in a cleaner light theme
&lt;/h2&gt;

&lt;p&gt;VisuaLeaf also includes a *&lt;strong&gt;&lt;em&gt;light theme&lt;/em&gt;&lt;/strong&gt;*.&lt;/p&gt;

&lt;p&gt;This is useful when you create tutorials, record videos, take screenshots, share your screen, or explain MongoDB work during a team call.&lt;/p&gt;

&lt;p&gt;Dark mode is still great for focused work.&lt;/p&gt;

&lt;p&gt;But light mode can make query builders, schema diagrams, charts, dashboards, and collection compare screens easier to present.&lt;/p&gt;

&lt;p&gt;For a visual MongoDB workspace, that matters.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpxae24n6d7wg3l80v5yj.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpxae24n6d7wg3l80v5yj.png" alt="visualeaf_light_theme" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Build MongoDB queries, aggregation pipelines, NoSQL schema diagrams, charts, dashboards, collection comparisons, tasks, and performance workflows in one visual workspace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;Download the Free Community Edition&lt;/a&gt; and start with a 14-day Pro trial.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>javascript</category>
      <category>database</category>
      <category>software</category>
    </item>
    <item>
      <title>MongoDB Schema Design: Embedded vs Referenced with Examples</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Wed, 01 Jul 2026 09:59:24 +0000</pubDate>
      <link>https://dev.to/visualeaf/mongodb-schema-design-embedded-vs-referenced-with-examples-4kf2</link>
      <guid>https://dev.to/visualeaf/mongodb-schema-design-embedded-vs-referenced-with-examples-4kf2</guid>
      <description>&lt;p&gt;When you design a MongoDB database, one of the first choices is this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Should this data stay inside the same document, or should it live in another collection?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the difference between &lt;strong&gt;&lt;em&gt;embedding&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;referencing&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Embedding&lt;/em&gt;&lt;/strong&gt; means the data is stored inside the document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Referencing&lt;/em&gt;&lt;/strong&gt; means the data is stored in another collection and connected with an &lt;code&gt;_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That’s the main difference.&lt;/p&gt;

&lt;p&gt;Let’s use a simple database called &lt;code&gt;streaming_platform_db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It has collections like &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;movies&lt;/code&gt;, &lt;code&gt;series&lt;/code&gt;, &lt;code&gt;episodes&lt;/code&gt;, &lt;code&gt;payments&lt;/code&gt;, &lt;code&gt;ratings&lt;/code&gt;, &lt;code&gt;watch_history&lt;/code&gt;, and &lt;code&gt;activity_logs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The database works like a basic streaming platform.&lt;/p&gt;

&lt;p&gt;A user can have a subscription, profiles, and devices. The same user can also make payments, watch content, rate movies, and create activity logs.&lt;/p&gt;

&lt;p&gt;That makes this database a good example because it uses both embedded data and referenced data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Schema Design
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;Visualeaf&lt;/a&gt;, I generated a &lt;a href="https://visualeaf.com/features/visual-schema/" rel="noopener noreferrer"&gt;schema diagram&lt;/a&gt; for the &lt;code&gt;streaming_platform_db&lt;/code&gt; database.&lt;/p&gt;

&lt;p&gt;This makes the structure easier to understand because I can see the collections and their relationships in one place.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvcq37d1jtgho1umgz6jy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvcq37d1jtgho1umgz6jy.png" alt="Visualeaf schema diagram for a MongoDB streaming platform database with users, movies, series, episodes, payments, ratings, watch history, and activity logs.*" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VisuaLeaf schema diagram for &lt;code&gt;streaming_platform_db&lt;/code&gt;, showing embedded fields and referenced collections.&lt;/p&gt;

&lt;p&gt;For example, the &lt;code&gt;users&lt;/code&gt; collection has fields like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;subscription
profiles
devices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These fields are stored inside each user document.&lt;/p&gt;

&lt;p&gt;That means they are &lt;strong&gt;&lt;em&gt;embedded&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But other collections, like &lt;code&gt;payments&lt;/code&gt;, &lt;code&gt;ratings&lt;/code&gt;, &lt;code&gt;watch_history&lt;/code&gt;, and &lt;code&gt;activity_logs&lt;/code&gt;, are connected to &lt;code&gt;users&lt;/code&gt; with &lt;code&gt;user_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means they are &lt;strong&gt;&lt;em&gt;referenced&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So the diagram shows the main idea very clearly:&lt;/p&gt;

&lt;p&gt;Some data lives &lt;strong&gt;&lt;em&gt;inside&lt;/em&gt;&lt;/strong&gt; a document.&lt;/p&gt;

&lt;p&gt;Some data lives in &lt;strong&gt;&lt;em&gt;another collection&lt;/em&gt;&lt;/strong&gt; and points back with an ID.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Example in Mongo Shell
&lt;/h2&gt;

&lt;p&gt;To make this easier to see, here is a small example from the &lt;code&gt;users&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;In this document, &lt;code&gt;subscription&lt;/code&gt;, &lt;code&gt;profiles&lt;/code&gt;, and &lt;code&gt;devices&lt;/code&gt; are stored inside the user document.&lt;/p&gt;

&lt;p&gt;That means they are &lt;strong&gt;&lt;em&gt;embedded&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.users.insertOne({
  full_name: "Oliver Smith",
  email: "oliver.smith@streaming.test",
  country: "UK",
  city: "London",

  subscription: {
    plan: "standard",
    status: "active"
  },

  profiles: [
    {
      profile_name: "Oliver",
      type: "adult",
      preferences: {
        favorite_genres: ["Action", "Sci-Fi"],
        subtitles: ["en"]
      }
    },
    {
      profile_name: "Kids",
      type: "kids",
      kids_mode: true
    }
  ],

  devices: [
    {
      type: "laptop",
      os: "Windows 11"
    }
  ]
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating this document in &lt;a href="https://visualeaf.com/features/mongo-shell/" rel="noopener noreferrer"&gt;Mongo Shell,&lt;/a&gt; Visualeaf makes the embedded structure easier to see. The fields are inside the &lt;code&gt;users&lt;/code&gt; document, not in separate collections.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg8hia6lcwdp8dy6n82p7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg8hia6lcwdp8dy6n82p7.png" alt="Embedded data in the users collection. The subscription, profiles, preferences, and devices are stored inside the same user document." width="671" height="812"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Embedded data in the &lt;code&gt;users&lt;/code&gt; collection. The subscription, profiles, preferences, and devices are stored inside the same user document.&lt;/p&gt;

&lt;p&gt;Now compare that with &lt;strong&gt;&lt;em&gt;referenced data.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Payments are not stored inside the user document. They live in a separate collection and point back to the user with &lt;code&gt;user_id&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;insertOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;user_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="s2"&gt;USER_ID_HERE&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="mf"&gt;12.99&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;EUR&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;paid_at&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;user_id&lt;/code&gt; connects the payment to the user.&lt;/p&gt;

&lt;p&gt;That is a &lt;strong&gt;&lt;em&gt;reference&lt;/em&gt;&lt;/strong&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flkrrj7hn3co6iwuvt498.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flkrrj7hn3co6iwuvt498.png" alt="Visualeaf MongoDB schema diagram showing the users collection connected to the payments collection with a one-to-many relationship through user_id." width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visualeaf schema view showing the reference between &lt;code&gt;users&lt;/code&gt; and &lt;code&gt;payments&lt;/code&gt; through &lt;code&gt;user_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One important thing to know: a MongoDB reference is not the same as a SQL foreign key.&lt;/p&gt;

&lt;p&gt;In SQL, a foreign key can enforce the relationship between two tables.&lt;/p&gt;

&lt;p&gt;In MongoDB, &lt;code&gt;_user_id_&lt;/code&gt;is just a field that stores another document’s &lt;em&gt;id&lt;/em&gt;`&lt;/p&gt;

&lt;p&gt;MongoDB does not automatically check that the user exists.&lt;/p&gt;

&lt;p&gt;So the difference from the main diagram is simple:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
users.devices       // embedded&lt;br&gt;
users.profiles      // embedded&lt;br&gt;
users.subscription  // embedded&lt;/p&gt;

&lt;p&gt;payments.user_id    // referenced&lt;br&gt;
ratings.user_id     // referenced&lt;br&gt;
watch_history.user_id // referenced&lt;br&gt;
activity_logs.user_id // referenced&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Embed&lt;/em&gt;&lt;/strong&gt; data when it belongs inside the document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Reference&lt;/em&gt;&lt;/strong&gt; data when it should stay in another collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where embedding fits
&lt;/h2&gt;

&lt;p&gt;Embedding is a good choice when your data is associated with one primary document.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
users&lt;br&gt;
 └── subscription&lt;br&gt;
 └── profiles&lt;br&gt;
      └── preferences&lt;br&gt;
 └── devices&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you open a user account, you will likely also want to see the subscription, profiles, and devices too.&lt;br&gt;&lt;br&gt;
So it makes sense to keep them together.&lt;br&gt;&lt;br&gt;
You do not need a separate collection for every small detail.&lt;/p&gt;

&lt;p&gt;Simple rule: &lt;strong&gt;&lt;em&gt;Embed data when it belongs to one parent and is usually read together.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Referencing Fits
&lt;/h2&gt;

&lt;p&gt;Referencing is a good choice when the data can grow or needs to stay separate.&lt;/p&gt;

&lt;p&gt;For example, payments should not be stored inside the user document.&lt;/p&gt;

&lt;p&gt;A user can have many payments over time. One payment this month, another payment next month, and so on.&lt;/p&gt;

&lt;p&gt;So it is cleaner to store payments in a separate collection.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
payments&lt;br&gt;
└── user_id&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;user_id&lt;/code&gt; field points back to the user.&lt;/p&gt;

&lt;p&gt;The same idea works for &lt;code&gt;ratings&lt;/code&gt;, &lt;code&gt;watch_history&lt;/code&gt;, and &lt;code&gt;activity_logs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;br&gt;
ratings&lt;br&gt;
 └── user_id&lt;br&gt;
 └── content_id&lt;/p&gt;

&lt;p&gt;watch_history&lt;br&gt;
 └── user_id&lt;br&gt;
 └── content_id&lt;/p&gt;

&lt;p&gt;activity_logs&lt;br&gt;
 └── user_id&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These records are related to the user, but they do not need to live inside the user document.&lt;/p&gt;

&lt;p&gt;They can grow fast, so they are better as separate collections.&lt;/p&gt;

&lt;p&gt;Simple rule:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Reference data when it can grow, repeat, or connect more than one collection.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Embed vs When to Reference
&lt;/h2&gt;

&lt;p&gt;Here is a simple way to decide.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://www.mongodb.com/docs/manual/data-modeling/schema-design-process/" rel="noopener noreferrer"&gt;MongoDB schema design&lt;/a&gt; is about deciding where your data should live.&lt;/p&gt;

&lt;p&gt;Some data makes more sense inside the same document.&lt;/p&gt;

&lt;p&gt;Other data makes more sense in a separate collection, connected with an ID.&lt;/p&gt;

&lt;p&gt;That is the difference between embedding and referencing.&lt;/p&gt;

&lt;p&gt;A GUI tool like &lt;a href="https://visualeaf.com/features/" rel="noopener noreferrer"&gt;Visualeaf&lt;/a&gt; makes this easier to understand because you can see the database structure visually.&lt;/p&gt;

&lt;p&gt;Instead of reading only raw JSON, you can see how collections connect, where data is nested, and how the schema is organized.&lt;/p&gt;

&lt;p&gt;This makes it easier to read, explain, and improve your MongoDB database.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fneheoyr3bvy5ogaehplt.png" alt="CTA Image" width="799" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try VisuaLeaf today!&lt;/p&gt;

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

</description>
      <category>mongodb</category>
      <category>database</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>MongoDB find() Query Examples for Beginners - Filter, Sort, Limit</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Tue, 30 Jun 2026 19:05:26 +0000</pubDate>
      <link>https://dev.to/visualeaf/mongodb-find-query-examples-for-beginners-filter-sort-limit-4a54</link>
      <guid>https://dev.to/visualeaf/mongodb-find-query-examples-for-beginners-filter-sort-limit-4a54</guid>
      <description>&lt;p&gt;When you use MongoDB, most of the time you are asking one simple thing:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;“Give me the documents that match this.”&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;This is what &lt;code&gt;find()&lt;/code&gt; does.&lt;/p&gt;

&lt;p&gt;It searches through a collection and finds the documents that fit your filter.&lt;/p&gt;

&lt;p&gt;Let’s take an example with the &lt;code&gt;orders&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;It could 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;customer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Oliver&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;total&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;paymentMethod&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;items&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;laptop&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;mouse&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;Nothing complicated here.&lt;/p&gt;

&lt;p&gt;It is just one order. Oliver paid $120 using her credit card for a laptop and a mouse.&lt;/p&gt;

&lt;p&gt;Let’s now see how you can ask MongoDB about the data.&lt;/p&gt;

&lt;p&gt;Before writing any query, it helps to quickly look at the collection itself.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt;, the &lt;a href="https://visualeaf.com/blog/how-to-explore-and-work-with-mongodb-data-visually/" rel="noopener noreferrer"&gt;Tree View makes it easy&lt;/a&gt; to explore the &lt;code&gt;orders&lt;/code&gt; collection and see what fields each document contains.&lt;/p&gt;

&lt;p&gt;That way, before you even write &lt;code&gt;find()&lt;/code&gt;, you already have a clear picture of the data you are 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgposkep584wh0k36mzep.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgposkep584wh0k36mzep.png" alt="VisuaLeaf Tree View showing the orders collection with fields like customer, status, total, paymentMethod, and items." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Show All Documents
&lt;/h2&gt;

&lt;p&gt;The simplest query is 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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query means:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Return all orders for me.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Since there is an empty &lt;code&gt;{}&lt;/code&gt;, no rule was added.&lt;/p&gt;

&lt;p&gt;There is nothing to filter in MongoDB, so it will return all data from the &lt;code&gt;orders&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;It is fine during testing, but not really in a live database environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find Orders by Status
&lt;/h2&gt;

&lt;p&gt;What if we wanted to look for paid orders 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;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;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;What that means is:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Find the orders that have status equal to paid.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;MongoDB checks each document.&lt;/p&gt;

&lt;p&gt;If the order has:&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it is selected.&lt;/p&gt;

&lt;p&gt;Otherwise, if the status is &lt;code&gt;"pending"&lt;/code&gt; or &lt;code&gt;"cancelled"&lt;/code&gt;, it is ignored.&lt;/p&gt;

&lt;p&gt;This is the fundamental concept of MongoDB filtering.&lt;/p&gt;

&lt;p&gt;If you run this query in the &lt;a href="https://visualeaf.com/features/mongo-shell/" rel="noopener noreferrer"&gt;VisuaLeaf shell&lt;/a&gt;, you can immediately see the matching documents.&lt;/p&gt;

&lt;p&gt;This is one of the easiest ways to understand what &lt;code&gt;find()&lt;/code&gt; does: you write a simple filter, run it, and MongoDB returns only the documents that match 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcnrqrx0cm6spq1p5sk4s.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcnrqrx0cm6spq1p5sk4s.png" alt="VisuaLeaf shell showing the query db.orders.find({ status: " width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Find Orders with Two Conditions
&lt;/h2&gt;

&lt;p&gt;And here’s an example request for orders that are paid and paid by card.&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;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;paymentMethod&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does this mean?&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Show orders which have status "paid" and payment method "card".&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Both conditions must apply.&lt;/p&gt;

&lt;p&gt;Which means the results won’t include all paid orders.&lt;/p&gt;

&lt;p&gt;Only paid orders that are paid by card.&lt;/p&gt;

&lt;p&gt;The easy way to remember this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Two fields in the same filter = AND
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Find Orders Greater Than a Number
&lt;/h2&gt;

&lt;p&gt;Sometimes we do not need to match exact values.&lt;/p&gt;

&lt;p&gt;We can find orders where the total is more than 120.&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;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;$gt&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$gt&lt;/code&gt; stands for *&lt;strong&gt;&lt;em&gt;greater than&lt;/em&gt;&lt;/strong&gt;*.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Find orders where the value of total is greater than 120.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Some important operators include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$gt   greater than
$gte  greater than or equal
$lt   less than
$lte  less than or equal
$ne   not equal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For 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;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;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;$lt&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Find orders where the value of total is less than 50.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;h2&gt;
  
  
  Find Orders with More Than One Accepted Value
&lt;/h2&gt;

&lt;p&gt;Suppose we have two types of payment accepted: card and PayPal.&lt;/p&gt;

&lt;p&gt;We can use &lt;code&gt;$in&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;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;paymentMethod&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;card&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;paypal&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;It means that:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Give me all orders that have payment method card or PayPal.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;$in&lt;/code&gt; operator can be used when one property needs to be checked against multiple values.&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;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;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;processing&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;It means that:&lt;/p&gt;

&lt;p&gt;**Give me all orders that are paid or in process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sort the Results
&lt;/h2&gt;

&lt;p&gt;A filter determines which documents will be returned to you.&lt;/p&gt;

&lt;p&gt;But ordering determines the order in which they appear.&lt;/p&gt;

&lt;p&gt;For instance,&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;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;total&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;Which means:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Give me the paid orders, and start from those with the highest totals.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;As we can see, &lt;code&gt;-1&lt;/code&gt; means descending order.&lt;/p&gt;

&lt;p&gt;Which means, higher numbers appear first.&lt;/p&gt;

&lt;p&gt;If we used &lt;code&gt;1&lt;/code&gt;, lower numbers would appear first.&lt;/p&gt;

&lt;p&gt;For instance,&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;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;total&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;Which means:&lt;/p&gt;

&lt;p&gt;**Give me the paid orders, and start from those with the lowest totals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limit the Results
&lt;/h2&gt;

&lt;p&gt;Often, you do not need to see all results that match your search.&lt;/p&gt;

&lt;p&gt;All you need is to see a few results.&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;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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this means is:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;I want to see only 5 paid orders.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;You may also add sort and limit together.&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;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="nf"&gt;sort&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="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;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this means is:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;I want to see the top 5 paid orders by total.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Your search becomes very meaningful.&lt;/p&gt;

&lt;p&gt;You no longer get all paid orders.&lt;br&gt;&lt;br&gt;
You get only the top 5.&lt;/p&gt;
&lt;h2&gt;
  
  
  Return Only Needed Fields
&lt;/h2&gt;

&lt;p&gt;In general, when running &lt;code&gt;find()&lt;/code&gt; command, MongoDB retrieves the whole document from the collection.&lt;/p&gt;

&lt;p&gt;However, sometimes you need only some fields of the 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;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="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="na"&gt;customer&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;total&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;_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="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the first block represents the filter criteria,&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;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;and the second one specifies the fields needed to be retrieved by MongoDB:&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;customer&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="nx"&gt;total&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="nx"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the field value is equal to &lt;code&gt;1&lt;/code&gt;, it will be included in the output.&lt;br&gt;&lt;br&gt;
&lt;code&gt;_id: 0&lt;/code&gt; indicates that you do not need the &lt;code&gt;_id&lt;/code&gt; field in the output.&lt;/p&gt;

&lt;p&gt;Thus, your output will 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;customer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Oliver&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="mi"&gt;120&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  One Query With All the Parts
&lt;/h2&gt;

&lt;p&gt;Here we bring everything together.&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="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;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;$gt&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="na"&gt;paymentMethod&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;card&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;paypal&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;customer&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;total&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;paymentMethod&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;_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="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;total&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, it seems longer.&lt;/p&gt;

&lt;p&gt;But here is how you read it normally:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Show me orders that are paid, have a total of more than 120, and have a paymentMethod of card or PayPal. Return the customer, total, and paymentMethod. Sort by descending total and limit to five results.&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;That is all there is to it.&lt;/p&gt;

&lt;p&gt;The query is no magic.&lt;/p&gt;

&lt;p&gt;It is just a question with some extra detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does It Seem Like MongoDB Queries Are Difficult?
&lt;/h2&gt;

&lt;p&gt;It seems like that because the queries use brackets within brackets.&lt;/p&gt;

&lt;p&gt;The logic itself, however, is simple.&lt;/p&gt;

&lt;p&gt;Firstly, choose the collection:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then ask to return the documents:&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="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then put the filter:&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;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;That 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;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;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;Just asks *&lt;strong&gt;&lt;em&gt;to find the orders that have the status paid&lt;/em&gt;&lt;/strong&gt;*.&lt;/p&gt;

&lt;p&gt;Once you treat the MongoDB queries as regular questions, everything becomes easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building MongoDB Queries Visually
&lt;/h2&gt;

&lt;p&gt;Writing MongoDB queries by hand is important.&lt;/p&gt;

&lt;p&gt;But when a query has more parts, it can be easier to build it step by step.&lt;/p&gt;

&lt;p&gt;For example, our final query does a few things at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;status equals paid
total greater than 120
paymentMethod is card or paypal
return only a few fields
sort by total
limit the results to 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not hard, but it is easy to miss a bracket or forget one part.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can &lt;a href="https://visualeaf.com/features/visual-query-builder/" rel="noopener noreferrer"&gt;build the same query visually&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You add the filters one by one, choose the fields you want to see, set the sort order, and limit the results.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvxx6vis10k4tin7qgwtd.gif" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvxx6vis10k4tin7qgwtd.gif" alt="VisuaLeaf Visual Query Builder showing filters for paid orders over 100, paymentMethod card or paypal, selected fields, sort by total descending, and limit 5" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The same MongoDB query built visually in VisuaLeaf, with filters, selected fields, sorting, and limit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The nice part is that you can see the result while building the query.&lt;/p&gt;

&lt;p&gt;So instead of writing the full query from scratch and hoping it works, you can build it slowly, check the output, and then use the generated MongoDB query when you need it.&lt;/p&gt;

&lt;p&gt;This is especially helpful when you are still learning MongoDB, or when you open a collection after some time and do not remember all the field names.&lt;/p&gt;

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

&lt;p&gt;A MongoDB query is simply a question that you ask of your database.&lt;/p&gt;

&lt;p&gt;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;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;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;means:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;What orders are paid?&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;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;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;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;$gt&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;translates to:&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;What orders are greater than 120?&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Start small.&lt;/p&gt;

&lt;p&gt;Add a condition at a time.&lt;/p&gt;

&lt;p&gt;Check the output.&lt;/p&gt;

&lt;p&gt;Only then do you add any sorting, limiting, or field projection.&lt;/p&gt;

&lt;p&gt;That is the simplest way to understand &lt;code&gt;find()&lt;/code&gt; queries in MongoDB.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa7eg2uxmbl6sqktjuxww.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;

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

</description>
      <category>mongodb</category>
      <category>javascript</category>
      <category>database</category>
      <category>basic</category>
    </item>
    <item>
      <title>MongoDB Access Control - Users, Roles, and Permissions</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Fri, 12 Jun 2026 05:29:11 +0000</pubDate>
      <link>https://dev.to/visualeaf/mongodb-access-control-users-roles-and-permissions-4hee</link>
      <guid>https://dev.to/visualeaf/mongodb-access-control-users-roles-and-permissions-4hee</guid>
      <description>&lt;p&gt;There are two major aspects when connecting to MongoDB.&lt;/p&gt;

&lt;p&gt;One of them is identifying yourself.&lt;/p&gt;

&lt;p&gt;The other one is defining what you are permitted to do.&lt;/p&gt;

&lt;p&gt;Both aspects are different from each other.&lt;/p&gt;

&lt;p&gt;A user could identify itself correctly by using its username and password, yet the user wouldn’t be able to perform any actions with databases, update any document within, add new users, or manage any roles.&lt;/p&gt;

&lt;p&gt;All these permissions are provided through RBAC.&lt;/p&gt;

&lt;p&gt;Role-Based Access Control, or RBAC, refers to the allocation of specific roles to users in MongoDB. Roles determine what actions can be performed on particular databases or collections.&lt;/p&gt;

&lt;p&gt;In my case, I decided to use the &lt;code&gt;streaming_platform_db&lt;/code&gt; database, whose collections include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users
movies
reviews
payments
subscriptions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is an appropriate choice as not all users would require the same access rights.&lt;/p&gt;

&lt;p&gt;For instance, the app requires writing operations.&lt;br&gt;&lt;br&gt;
The data analyst may require reading operations.&lt;br&gt;&lt;br&gt;
The support agent requires viewing users, payments, and subscriptions.&lt;br&gt;&lt;br&gt;
Administrative rights should be reserved for admin tasks.&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%2Fx3sys7v9yl0pgffrj59g.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%2Fx3sys7v9yl0pgffrj59g.png" alt="VisuaLeaf RBAC Dashboard showing MongoDB users, assigned roles, databases, and active sessions." width="799" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A quick overview of MongoDB users, roles, databases, and active sessions in VisuaLeaf.&lt;/p&gt;
&lt;h2&gt;
  
  
  Authentication vs. Authorization
&lt;/h2&gt;

&lt;p&gt;Authentication provides an answer to the following question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is this really the person they claim to be?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authorization provides the answer to the following question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What can this person do?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other words, even if &lt;code&gt;support_agent&lt;/code&gt; succeeds in logging into MongoDB, it should prevent them from executing update, insert, and delete queries if their role is &lt;code&gt;read&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is how it should be.&lt;/p&gt;

&lt;p&gt;The login was successful. The operation wasn’t.&lt;/p&gt;

&lt;p&gt;This proves that the role works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Environment Configuration
&lt;/h3&gt;

&lt;p&gt;I have configured some users in VisuaLeaf with various roles as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data_analyst@streaming_platform_db   read@streaming_platform_db
streamflix_app@admin                 readWrite@streaming_platform_db
support_agent@admin                  supportViewer@admin, read@streaming_platform_db
admin@admin                          root@admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple configuration, yet it includes most possible scenarios.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;admin&lt;/code&gt; user is used for administrative purposes.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;streamflix_app&lt;/code&gt; user is used for applications.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;data_analyst&lt;/code&gt; user is used for generating and reviewing reports.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;support_agent&lt;/code&gt; user is used for support activities that require data verification without making any changes.&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%2Faqa5baxr3n77qvdc6ubb.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%2Faqa5baxr3n77qvdc6ubb.png" alt="VisuaLeaf Users tab showing MongoDB users with SCRAM authentication and assigned roles, including root, readWrite, read, and supportViewer." width="799" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB users and their assigned roles in VisuaLeaf.&lt;/p&gt;

&lt;h2&gt;
  
  
  Role Definition in MongoDB
&lt;/h2&gt;

&lt;p&gt;The MongoDB role is defined through privileges.&lt;/p&gt;

&lt;p&gt;The privilege means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This operation is permitted on this database/resource.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operation can be &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;insert&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, or &lt;code&gt;remove&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The resource can be a database or an exact collection.&lt;/p&gt;

&lt;p&gt;Thus, the role is more than just its name; it is a combination of rules.&lt;/p&gt;

&lt;p&gt;For instance,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;read@streaming_platform_db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means that the user has the permission to read information from &lt;code&gt;streaming_platform_db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It doesn’t imply the user is granted access to read all the databases present on the server.&lt;/p&gt;

&lt;p&gt;That’s because of the latter part - the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built-In Roles You Will Use Often
&lt;/h2&gt;

&lt;p&gt;MongoDB has numerous built-in default roles, but you don't have to start with all of them.&lt;/p&gt;

&lt;p&gt;Most beginners will probably use the following ones first:&lt;/p&gt;

&lt;p&gt;Here comes the common temptation to use the &lt;code&gt;root&lt;/code&gt; role in every case, which will help avoid access issues.&lt;/p&gt;

&lt;p&gt;It will work just fine at the early stage.&lt;/p&gt;

&lt;p&gt;However, the problem is that, over time, it will become difficult to trace which user can make changes.&lt;/p&gt;

&lt;p&gt;A proper solution is to grant each user only those permissions required for their work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Admin User
&lt;/h2&gt;

&lt;p&gt;The admin user normally exists in the &lt;code&gt;admin&lt;/code&gt; database.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://visualeaf.com/features/mongo-shell/" rel="noopener noreferrer"&gt;Mongo shell&lt;/a&gt;, it may be created like so:&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;use&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;passwordPrompt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;roles&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;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&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;It gives you total administrative access.&lt;/p&gt;

&lt;p&gt;Do not use it for anything except administrative purposes.&lt;/p&gt;

&lt;p&gt;It is not needed by the application to simply save review data or manage subscriptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Application User
&lt;/h2&gt;

&lt;p&gt;The application must be able to read and write the data stored in the application’s database.&lt;/p&gt;

&lt;p&gt;For this purpose, we can rely on the &lt;code&gt;readWrite&lt;/code&gt; permission.&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;use&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;streamflix_app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;passwordPrompt&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;roles&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;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;readWrite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;streaming_platform_db&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;This user will be able to manipulate the documents in the &lt;code&gt;streaming_platform_db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It will have the ability to create new users, save their reviews, update their subscriptions, and record their payments.&lt;/p&gt;

&lt;p&gt;However, it will not be able to manage users and roles at the server level.&lt;/p&gt;

&lt;p&gt;And this was the very idea behind the user creation process.&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%2Fqcpcl6l0f415mzsf1xn1.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%2Fqcpcl6l0f415mzsf1xn1.png" alt="VisuaLeaf Create User dialog assigning the readWrite role to the streamflix_app MongoDB user." width="799" height="719"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating an application user with read and write access to the streaming database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Support Role with Limited Access
&lt;/h2&gt;

&lt;p&gt;The application user needs &lt;code&gt;readWrite&lt;/code&gt; access because the app has to save reviews, update subscriptions, and record payments.&lt;/p&gt;

&lt;p&gt;A support user is different.&lt;/p&gt;

&lt;p&gt;Support usually needs to check information, not change it.&lt;/p&gt;

&lt;p&gt;For example, a support agent may need to answer questions like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Does this user exist?
Was the payment created?
Is the subscription active?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Giving this user full database access would be too much.&lt;/p&gt;

&lt;p&gt;A better option is to create a smaller custom role for support work. In this example, I use a role called &lt;code&gt;supportViewer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, I can create this role from the Create New Role dialog. The role is created in the &lt;code&gt;admin&lt;/code&gt; database, but the permission applies to &lt;code&gt;streaming_platform_db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here, I selected two actions:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This means the role can read documents and list the collections in the database.&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%2Fd5eqgu0r27gjmxydc5rm.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%2Fd5eqgu0r27gjmxydc5rm.png" alt="VisuaLeaf Create New Role dialog for creating the supportViewer MongoDB role with find and listCollections permissions." width="800" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://visualeaf.com/features/mongo-shell/" rel="noopener noreferrer"&gt;Mongo shell&lt;/a&gt;, the same role would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use admin

db.createRole({
  role: "supportViewer",
  privileges: [
    {
      resource: { db: "streaming_platform_db", collection: "" },
      actions: ["find", "listCollections"]
    }
  ],
  roles: []
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The empty collection name means the permission applies to all collections in &lt;code&gt;streaming_platform_db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;find&lt;/code&gt; action lets the user read documents.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;listCollections&lt;/code&gt; action lets the user see which collections exist.&lt;/p&gt;

&lt;p&gt;It does not include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insert
update
remove
dropCollection
createIndex
dropIndex
userAdmin
root
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this role can check data, but it does not have full admin power.&lt;/p&gt;

&lt;p&gt;That is the point of a custom role: give enough access for the task, but not more than needed.&lt;/p&gt;

&lt;p&gt;In the Roles tab, VisuaLeaf also shows custom roles next to the built-in MongoDB roles. In this example, &lt;code&gt;supportViewer&lt;/code&gt; appears as a custom role and is assigned to &lt;code&gt;support_agent&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%2Fzh2a2imxz5bgvhlg5adq.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%2Fzh2a2imxz5bgvhlg5adq.png" alt="VisuaLeaf Roles tab showing built-in MongoDB roles and a custom supportViewer role." width="799" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built-in and custom MongoDB roles shown in VisuaLeaf.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking a User’s Access
&lt;/h2&gt;

&lt;p&gt;Once you’ve added users and roles, it is also good to verify what MongoDB actually saved.&lt;/p&gt;

&lt;p&gt;To view details about the support user:&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;use&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;support_agent&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;To display the user’s privileges:&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;use&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;support_agent&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;showPrivileges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this example also uses the &lt;code&gt;supportViewer&lt;/code&gt; custom role, you can check that role too:&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;use&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;

&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;supportViewer&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;showPrivileges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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 when something seems off.&lt;/p&gt;

&lt;p&gt;The user could have been created using the wrong authentication database.&lt;/p&gt;

&lt;p&gt;The role may point to the wrong database.&lt;/p&gt;

&lt;p&gt;Or the user may have the right role name, but not the privileges you expected.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, you can review this information from the Users tab instead of checking everything only from the shell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting With a User
&lt;/h2&gt;

&lt;p&gt;When you connect with a MongoDB user, make sure you use the right authentication database.&lt;/p&gt;

&lt;p&gt;For example, if &lt;code&gt;support_agent&lt;/code&gt; was created in &lt;code&gt;admin&lt;/code&gt;, connect like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"support_agent"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"yourPassword"&lt;/span&gt; &lt;span class="nt"&gt;--authenticationDatabase&lt;/span&gt; &lt;span class="s2"&gt;"admin"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then switch to the app database:&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;use&lt;/span&gt; &lt;span class="nx"&gt;streaming_platform_db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A read query should work:&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;find&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But a write should fail:&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;insertOne&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="s2"&gt;Test User&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 user only has &lt;code&gt;read&lt;/code&gt;, that failure is expected.&lt;/p&gt;

&lt;p&gt;It means MongoDB is blocking writes for that user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where VisuaLeaf Helps
&lt;/h2&gt;

&lt;p&gt;Mongo shell commands are useful because they show exactly what MongoDB is doing.&lt;/p&gt;

&lt;p&gt;But when you have several users and roles, it is easier to review them visually.&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, the RBAC Dashboard shows users, roles, databases, and active sessions in one place. You can quickly see which users exist, which roles they have, and whether they have read-only, read-write, or admin access.&lt;/p&gt;

&lt;p&gt;This helps when you return to a project later and need to understand the access setup quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple Rule for MongoDB Permissions
&lt;/h2&gt;

&lt;p&gt;Start with the smallest role that works.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;read&lt;/code&gt; when someone only needs to view data.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;readWrite&lt;/code&gt; when the application needs to change data.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;dbAdmin&lt;/code&gt; or &lt;code&gt;userAdmin&lt;/code&gt; for specific admin tasks.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;root&lt;/code&gt; only when full control is really needed.&lt;/p&gt;

&lt;p&gt;Do not give admin permissions just to avoid access errors. That shortcut usually creates problems later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Setup
&lt;/h2&gt;

&lt;p&gt;In this example, the setup looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;admin           -&amp;gt; root
streamflix_app  -&amp;gt; readWrite
data_analyst    -&amp;gt; read
support_agent   -&amp;gt; supportViewer, read
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each user has a clear purpose.&lt;/p&gt;

&lt;p&gt;The admin user handles administration.&lt;br&gt;&lt;br&gt;
The app user works with application data.&lt;br&gt;&lt;br&gt;
The analyst reads data for reports.&lt;br&gt;&lt;br&gt;
The support user can check support-related records without changing them.&lt;/p&gt;

&lt;p&gt;This is the main idea behind RBAC in MongoDB.&lt;/p&gt;

&lt;p&gt;Give users enough access to do their work, but not more than they need.&lt;/p&gt;

&lt;p&gt;Learn more about our RBAC Dashboard feature here: &lt;a href="https://visualeaf.com/features/rbac-dashboard/" rel="noopener noreferrer"&gt;RBAC Dashboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to download VisuaLeaf, you can do it from here: &lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;Download VisuaLeaf&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>database</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <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>
  </channel>
</rss>
