<?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>MongoDB Schema Design: Build or Reverse Engineer Visually</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Thu, 06 Aug 2026 11:45:16 +0000</pubDate>
      <link>https://dev.to/visualeaf/mongodb-schema-design-build-or-reverse-engineer-visually-5d28</link>
      <guid>https://dev.to/visualeaf/mongodb-schema-design-build-or-reverse-engineer-visually-5d28</guid>
      <description>&lt;p&gt;MongoDB collections can become difficult to understand once they contain nested objects, arrays, references, and documents with slightly different structures.&lt;/p&gt;

&lt;p&gt;Looking at one JSON document at a time shows you the data, but not the complete model. It is harder to see how collections connect, which fields use inconsistent BSON types, or whether a value is embedded or referenced elsewhere.&lt;/p&gt;

&lt;p&gt;The opposite problem happens when the database does not exist yet. You may know which collections and fields you need, but reviewing the design across separate JSON files or application models is not easy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/features/visual-schema/" rel="noopener noreferrer"&gt;VisuaLeaf’s Visual Schema&lt;/a&gt; supports both directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a diagram from an existing MongoDB database.&lt;/li&gt;
&lt;li&gt;Design a new schema from an empty diagram.&lt;/li&gt;
&lt;li&gt;Keep the schema virtual or materialize it into real collections.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I tested both workflows using a travel-planning database containing collections such as &lt;code&gt;travelers&lt;/code&gt;, &lt;code&gt;places&lt;/code&gt;, &lt;code&gt;flights&lt;/code&gt;, &lt;code&gt;accommodations&lt;/code&gt;, &lt;code&gt;restaurants&lt;/code&gt;, &lt;code&gt;activities&lt;/code&gt;, &lt;code&gt;carRentals&lt;/code&gt;, and &lt;code&gt;vacationPlans&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3df2kfd2ac64dpf9s0rn.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%2F3df2kfd2ac64dpf9s0rn.png" alt="MongoDB Visual Schema in VisuaLeaf showing the central vacationPlans collection connected to travelers, flights, accommodations, restaurants, car rentals, activities, and places." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VisuaLeaf generates a visual MongoDB schema showing collections, fields, BSON types, and relationships in the &lt;code&gt;TravelPlannerDemo&lt;/code&gt; database.&lt;/p&gt;

&lt;p&gt;Although this guide focuses on MongoDB, VisuaLeaf’s Visual Schema can also be used with &lt;a href="https://visualeaf.com/database/" rel="noopener noreferrer"&gt;SQL databases.&lt;/a&gt; If you’re deciding which database model fits your project or want to compare their structures, read &lt;a href="https://visualeaf.com/blog/mongodb-vs-postgresql-whats-the-difference/" rel="noopener noreferrer"&gt;MongoDB vs PostgreSQL: What’s the Difference?&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reverse engineer an existing MongoDB database
&lt;/h3&gt;

&lt;p&gt;If your database already contains data, you can generate a Visual Schema from its collections.&lt;/p&gt;

&lt;p&gt;Connect to MongoDB, open *&lt;strong&gt;&lt;em&gt;Visual Schema&lt;/em&gt;&lt;/strong&gt;*, and select the database you want to analyze. VisuaLeaf reads the existing documents and creates a diagram containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;collections and fields;&lt;/li&gt;
&lt;li&gt;detected BSON types;&lt;/li&gt;
&lt;li&gt;embedded objects;&lt;/li&gt;
&lt;li&gt;arrays and their nested fields;&lt;/li&gt;
&lt;li&gt;detected relationships between collections.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my &lt;code&gt;TravelPlannerDemo&lt;/code&gt; database, the generated diagram included the main travel collections and their nested structures.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;vacationPlans&lt;/code&gt; contains simple fields such as &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, and &lt;code&gt;createdAt&lt;/code&gt;, but it also includes more complex structures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;budget&lt;/code&gt; and &lt;code&gt;dates&lt;/code&gt; as embedded objects;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;itinerary&lt;/code&gt;, &lt;code&gt;checklist&lt;/code&gt;, and &lt;code&gt;documents&lt;/code&gt; as arrays;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;destinationIds&lt;/code&gt; and &lt;code&gt;travelerIds&lt;/code&gt; as arrays of references;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ownerTravelerId&lt;/code&gt; and &lt;code&gt;selectedAccommodationId&lt;/code&gt; as individual references.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of opening several documents to understand how these fields fit together, I could inspect the structure in one diagram.&lt;/p&gt;

&lt;p&gt;This is particularly useful when you are working with a database you did not design, or when the structure has changed, but its documentation has not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the detected structure
&lt;/h2&gt;

&lt;p&gt;Here’s the trap most of us fall into: reverse-engineering a database shows what’s currently stored, not what was actually intended.&lt;/p&gt;

&lt;p&gt;MongoDB allows documents in the same collection to have different fields and BSON types. For example, most documents might store a date correctly:&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;createdAt&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-07-18T09:30: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;while an older import stores it as a string:&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;createdAt&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-07-18&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;These values may look similar in a table, but one has the BSON type &lt;code&gt;date&lt;/code&gt; and the other has the type &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same problem can occur with identifiers. A field such as &lt;code&gt;ownerTravelerId&lt;/code&gt; may contain an &lt;code&gt;ObjectId&lt;/code&gt; in most documents but a string in others. That difference matters when you try to connect it to &lt;code&gt;travelers._id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The generated schema represents the data VisuaLeaf analyzed. Rare fields may also be absent if they do not appear in the sampled documents. Review unusual records and any fields with multiple detected types before using the diagram as your final model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review and add relationships
&lt;/h2&gt;

&lt;p&gt;MongoDB does not store relationships as enforced foreign keys. It stores the reference value, but the meaning of that value often needs to be confirmed.&lt;/p&gt;

&lt;p&gt;In the travel database, relationships can connect fields such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vacationPlans.ownerTravelerId → travelers._id
vacationPlans.travelerIds[] → travelers._id
vacationPlans.destinationIds[] → places._id
vacationPlans.selectedAccommodationId → accommodations._id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other collections use similar connections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;accommodations.placeId → places._id
restaurants.placeId → places._id
activities.placeId → places._id
flights.passengers.travelerId → travelers._id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check both ends before accepting or adding a relationship. An &lt;code&gt;ObjectId&lt;/code&gt; does not match a string containing the same characters.&lt;/p&gt;

&lt;p&gt;For example, these two values use different BSON types:&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="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;66af9138ad73c91224345c10&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;66af9138ad73c91224345c10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diagram can document a relationship, but it does not make MongoDB enforce it. Your application can still insert an &lt;code&gt;ownerTravelerId&lt;/code&gt; that does not exist in &lt;code&gt;travelers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The generated diagram may also need some visual cleanup. In a database with many related collections, lines can overlap and detected connections may not represent the relationship you intended. Reposition the collections and review each relationship rather than accepting every connection without checking.&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%2Fdlhmsx6fe1ms6dl1ndug.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%2Fdlhmsx6fe1ms6dl1ndug.png" alt="Close-up of a MongoDB schema diagram in VisuaLeaf showing nested fields, BSON types, arrays, and relationships between vacation plans, places, and accommodations." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A closer look at nested fields, BSON types, arrays, and relationships between&lt;/strong&gt; &lt;em&gt;`_vacationPlans&lt;/em&gt;&lt;code&gt;___,__ _&lt;/code&gt;&lt;em&gt;places&lt;/em&gt;&lt;code&gt;___, and__ _&lt;/code&gt;&lt;em&gt;accommodations&lt;/em&gt;`_ &lt;strong&gt;in VisuaLeaf.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Modify the generated schema
&lt;/h2&gt;

&lt;p&gt;A reverse-engineered schema does not have to remain a read-only picture of the current database.&lt;/p&gt;

&lt;p&gt;You can use it as a starting point and then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add or remove fields;&lt;/li&gt;
&lt;li&gt;correct BSON types;&lt;/li&gt;
&lt;li&gt;define embedded objects and arrays;&lt;/li&gt;
&lt;li&gt;add missing relationships;&lt;/li&gt;
&lt;li&gt;remove incorrect relationships;&lt;/li&gt;
&lt;li&gt;reorganize the diagram.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example, I added a new optional &lt;code&gt;travelStyle&lt;/code&gt; field to &lt;code&gt;vacationPlans&lt;/code&gt;. I also manually connected &lt;code&gt;destinationIds&lt;/code&gt; to &lt;code&gt;places._id&lt;/code&gt; to represent the reference between the two 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%2Fhvmgwyzbmksmydxhiroc.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%2Fhvmgwyzbmksmydxhiroc.png" alt="Editing the vacationPlans MongoDB schema in VisuaLeaf by adding the optional travelStyle field with the String BSON type." width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same collection contains embedded data as well. The &lt;code&gt;budget&lt;/code&gt; object belongs to one vacation plan, so storing it inside the document keeps the related values together. &lt;code&gt;destinationIds&lt;/code&gt;, however, contains references to documents stored in the &lt;code&gt;places&lt;/code&gt; collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vacationPlans
├── budget
│   ├── currency
│   ├── estimatedTotal
│   └── paidSoFar
├── dates
├── itinerary[]
├── ownerTravelerId
├── travelerIds[]
└── destinationIds[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows both modeling approaches in the same collection: embedded data for information owned by the vacation plan and references for information stored elsewhere and reused.&lt;/p&gt;

&lt;p&gt;Changing the virtual schema does not automatically migrate existing documents. If you rename a field, change its type, or move it into an embedded object, the records already stored in MongoDB remain unchanged.&lt;/p&gt;

&lt;p&gt;The diagram describes the proposed model. Data migration remains a separate operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design a new MongoDB schema from scratch
&lt;/h2&gt;

&lt;p&gt;You can also use Visual Schema before the database exists.&lt;/p&gt;

&lt;p&gt;Start with an empty diagram and add the collections you need. You can then define their fields, BSON types, embedded structures, arrays, and relationships.&lt;/p&gt;

&lt;p&gt;For this example, I created a small tour-booking schema with two collections:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Collection&lt;/th&gt;
&lt;th&gt;Example fields&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;departures&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;_id&lt;/code&gt;, &lt;code&gt;packageId&lt;/code&gt;, &lt;code&gt;startDate&lt;/code&gt;, &lt;code&gt;capacity&lt;/code&gt;, &lt;code&gt;meetingPoint&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reservations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;_id&lt;/code&gt;, &lt;code&gt;departureId&lt;/code&gt;, &lt;code&gt;bookingReference&lt;/code&gt;, &lt;code&gt;leadGuest&lt;/code&gt;, &lt;code&gt;totalAmount&lt;/code&gt;, &lt;code&gt;paymentStatus&lt;/code&gt;, &lt;code&gt;createdAt&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;leadGuest&lt;/code&gt; field is an embedded object containing fields such as &lt;code&gt;fullName&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt;. The relationship connects:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reservations.departureId → departures._id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This represents a one-to-many relationship: one departure can have multiple reservations.&lt;/p&gt;

&lt;p&gt;Defining the schema visually makes several problems easier to notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;references pointing to the wrong field;&lt;/li&gt;
&lt;li&gt;incorrect BSON types;&lt;/li&gt;
&lt;li&gt;fields that should be grouped inside an embedded object;&lt;/li&gt;
&lt;li&gt;missing or unnecessary relationships;&lt;/li&gt;
&lt;li&gt;inconsistent field names between collections.&lt;/li&gt;
&lt;/ul&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%2Fhebkwgkol5au017x1dvf.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%2Fhebkwgkol5au017x1dvf.png" alt="VisuaLeaf visual schema showing departures and reservations connected through departures._id and reservations.departureId, with BSON types and an embedded leadGuest object." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After completing the design, save the schema and bind it to the MongoDB connection where you want to create the collections. The diagram remains a virtual model until you materialize it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the schema virtual or materialize it
&lt;/h2&gt;

&lt;p&gt;The diagram can remain virtual if you only need it for documentation, planning, or discussing changes with your team.&lt;/p&gt;

&lt;p&gt;Nothing is created in MongoDB until you choose to materialize it.&lt;/p&gt;

&lt;p&gt;When the design is ready, save it and bind it to the MongoDB connection and target database. You can then click *&lt;strong&gt;&lt;em&gt;Materialize&lt;/em&gt;&lt;/strong&gt;* to review the collections and generated validators before applying the schema.&lt;/p&gt;

&lt;p&gt;This allows both workflows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Existing MongoDB database → Visual Schema
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Visual Schema → MongoDB database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can therefore reverse engineer an existing database such as &lt;code&gt;TravelPlannerDemo&lt;/code&gt;, modify its virtual schema, and materialize the result into a separate test database.  &lt;/p&gt;

&lt;p&gt;You can also begin with an empty diagram, as I did with &lt;code&gt;TourBookingSchema&lt;/code&gt;, and create a new database from that design.&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%2Fulny3425f5e17xilwyqe.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%2Fulny3425f5e17xilwyqe.png" alt="VisuaLeaf Materialize screen showing the reservations collection, its BSON fields, embedded leadGuest object, generated MongoDB validator, and Apply to Database button." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose whether to attach validators
&lt;/h2&gt;

&lt;p&gt;Materializing a schema does not require you to enforce every field and BSON type.&lt;/p&gt;

&lt;p&gt;The materialization screen lets you review the JSON Schema generated for each collection. You can then decide whether MongoDB should use it as a &lt;code&gt;$jsonSchema&lt;/code&gt; validator.&lt;/p&gt;

&lt;p&gt;If you want to create the collections without enforcing the schema, leave *&lt;strong&gt;&lt;em&gt;Attach validator&lt;/em&gt;&lt;/strong&gt;* disabled.&lt;/p&gt;

&lt;p&gt;These are separate decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The visual schema describes the intended structure.&lt;/li&gt;
&lt;li&gt;Materialization creates the collections in MongoDB.&lt;/li&gt;
&lt;li&gt;The generated JSON Schema describes the field and type rules.&lt;/li&gt;
&lt;li&gt;The attached validator makes MongoDB enforce those rules during writes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A field is mandatory only if it is included in the schema’s &lt;code&gt;required&lt;/code&gt; array. Otherwise, its BSON type is checked only when the field is present.&lt;/p&gt;

&lt;p&gt;This distinction matters when your application still writes inconsistent data.&lt;/p&gt;

&lt;p&gt;Suppose the generated schema expects:&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;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;bsonType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&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;If the application sends this instead:&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;createdAt&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-08-03&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;MongoDB will reject the write when the validator is attached. A document validation failure commonly returns MongoDB error code &lt;code&gt;121&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The solution is not necessarily to remove validation. First check what your application actually sends. You may need to fix the value before inserting it or adjust the schema if both types are intentionally supported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the materialization plan
&lt;/h2&gt;

&lt;p&gt;Before clicking *&lt;strong&gt;&lt;em&gt;Apply to Database&lt;/em&gt;&lt;/strong&gt;*, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the selected connection and database;&lt;/li&gt;
&lt;li&gt;which collections will be created;&lt;/li&gt;
&lt;li&gt;which collections already exist;&lt;/li&gt;
&lt;li&gt;collection and field names;&lt;/li&gt;
&lt;li&gt;BSON types;&lt;/li&gt;
&lt;li&gt;embedded objects and arrays;&lt;/li&gt;
&lt;li&gt;relationships in the visual diagram;&lt;/li&gt;
&lt;li&gt;generated JSON Schemas;&lt;/li&gt;
&lt;li&gt;which collections have the *&lt;strong&gt;&lt;em&gt;Attach validator&lt;/em&gt;&lt;/strong&gt;* enabled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first test, use a new database instead of applying the model directly to an existing one.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This makes the result easier to inspect and avoids mixing the materialized collections with the original &lt;code&gt;TravelPlannerDemo&lt;/code&gt; data.&lt;/p&gt;

&lt;p&gt;If you materialize changes against a database that already contains records, changing &lt;code&gt;reservations.departureId&lt;/code&gt; from &lt;code&gt;String&lt;/code&gt; to &lt;code&gt;ObjectId&lt;/code&gt; in the diagram will not convert the stored values. Data migration remains a separate operation.&lt;/p&gt;

&lt;p&gt;It also does not create enforced foreign keys. The relationship between &lt;code&gt;reservations.departureId&lt;/code&gt; and &lt;code&gt;departures._id&lt;/code&gt; remains part of the model, but your application must maintain valid references.&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%2F0sve8uozl6kk4og7t34z.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%2F0sve8uozl6kk4og7t34z.png" alt="VisuaLeaf showing the newly created departures and reservations collections in MongoDB." width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the result
&lt;/h2&gt;

&lt;p&gt;After applying the materialization plan, open the target database and confirm that the &lt;code&gt;departures&lt;/code&gt; and &lt;code&gt;reservations&lt;/code&gt; collections were created.&lt;/p&gt;

&lt;p&gt;If you enabled *&lt;strong&gt;&lt;em&gt;Attach validator&lt;/em&gt;&lt;/strong&gt;*, inspect the validation settings and test them with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one valid document that should be accepted;&lt;/li&gt;
&lt;li&gt;one invalid document that should be rejected.&lt;/li&gt;
&lt;/ul&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%2Frhcezatzy0lhnfk0b1zh.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%2Frhcezatzy0lhnfk0b1zh.png" alt="Split-screen MongoDB shell in VisuaLeaf showing a valid reservation inserted successfully and an invalid reservation rejected by JSON Schema validation because several BSON types do not match." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you left the option disabled, the collections should still exist, but MongoDB will continue accepting documents with different structures.&lt;/p&gt;

&lt;p&gt;Also remember that a validator does not replace indexes. Fields used for lookups and filtering may still need indexes, such as:&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;reservations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIndex&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;departureId&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;createdAt&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;departures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIndex&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;startDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validators control document structure. Indexes support query performance and can enforce uniqueness when created with the &lt;code&gt;unique&lt;/code&gt; option.&lt;br&gt;&lt;br&gt;
Relationships explain how collections connect, but MongoDB does not enforce them as foreign keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  One schema, two directions
&lt;/h2&gt;

&lt;p&gt;Visual Schema is useful when you inherit an existing MongoDB database and need to understand its structure. It is also useful before you create the first collection.&lt;/p&gt;

&lt;p&gt;In my travel-planning example, I could generate a diagram containing &lt;code&gt;travelers&lt;/code&gt;, &lt;code&gt;places&lt;/code&gt;, &lt;code&gt;flights&lt;/code&gt;, &lt;code&gt;accommodations&lt;/code&gt;, &lt;code&gt;activities&lt;/code&gt;, &lt;code&gt;vacationPlans&lt;/code&gt;, and the other related collections. I could inspect nested structures such as &lt;code&gt;budget&lt;/code&gt; and &lt;code&gt;itinerary&lt;/code&gt;, review the references, and correct the model where necessary.&lt;/p&gt;

&lt;p&gt;The same workspace also supports the opposite workflow. You can start with an empty diagram, design the collections visually, and then decide whether to keep the model virtual or materialize it into MongoDB.&lt;/p&gt;

&lt;p&gt;When you materialize it, attaching the generated &lt;a href="https://visualeaf.com/blog/mongodb-json-schema-validation/" rel="noopener noreferrer"&gt;JSON Schema validators&lt;/a&gt; remains optional.&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Want to turn your MongoDB database into a diagram—or your diagram into a database?&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/download" rel="noopener noreferrer"&gt;Download VisuaLeaf&lt;/a&gt; and generate a schema from your existing MongoDB database, or design a new one from scratch.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>database</category>
      <category>javascript</category>
      <category>software</category>
    </item>
    <item>
      <title>Which MongoDB Client Handles Large Collections Best: VisuaLeaf vs Compass vs Studio 3T</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Tue, 04 Aug 2026 07:56:19 +0000</pubDate>
      <link>https://dev.to/visualeaf/which-mongodb-client-handles-large-collections-best-visualeaf-vs-compass-vs-studio-3t-1jam</link>
      <guid>https://dev.to/visualeaf/which-mongodb-client-handles-large-collections-best-visualeaf-vs-compass-vs-studio-3t-1jam</guid>
      <description>&lt;p&gt;A MongoDB client can feel fast with a few hundred documents and become frustrating as soon as the result grows.&lt;/p&gt;

&lt;p&gt;The database is not always the problem. MongoDB may finish the query while the desktop client is still fetching batches, converting BSON values, and building thousands of rows or JSON blocks.&lt;/p&gt;

&lt;p&gt;I tested VisuaLeaf, MongoDB Compass, and Studio 3T with the same collection of 50,844 documents. Then I tested three related workflows: comparing collections, automating repeated work, and investigating an unindexed query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test setup
&lt;/h2&gt;

&lt;p&gt;I ran all three applications on the same HP laptop with 16 GB of RAM and Windows 11 Pro. Each application was updated to the latest version available when I ran the test. All three connected to the same MongoDB database through the same internet connection and opened the same &lt;code&gt;largeCollection&lt;/code&gt;. The collection contained nested objects and arrays, not only flat fields.&lt;/p&gt;

&lt;p&gt;For the first test, I opened the collection without a filter, projection, or custom limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.largeCollection.find({})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is what happened:&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 1: What the large-result test actually shows
&lt;/h3&gt;

&lt;p&gt;The three clients made different choices.&lt;/p&gt;

&lt;p&gt;VisuaLeaf allowed one continuous result. That is useful when you need to scroll through a large set, select many documents, inspect distant rows, or export the current result without moving through pages.&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%2Fuaranufuy6h5x7sazkjw.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%2Fuaranufuy6h5x7sazkjw.png" alt="VisuaLeaf displaying 50,000 MongoDB documents with a load time of 13.481 seconds." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VisuaLeaf loaded 50,000 documents in one result in 13.481 seconds.&lt;/p&gt;

&lt;p&gt;Compass limited the amount of data visible at once. This protects the interface from an unexpectedly large query and works well when you only need to inspect a sample, edit one document, or confirm a filter. The tradeoff is that browsing the whole collection requires hundreds of pages.&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%2Fwm1gf7v40vgutjfgfojd.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%2Fwm1gf7v40vgutjfgfojd.png" alt="MongoDB Compass showing documents 1–100 of 50,844 with page-size options up to 100." width="799" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB Compass displayed the collection in pages of up to 100 documents.&lt;/p&gt;

&lt;p&gt;Studio 3T did not finish this particular operation before I stopped it. That does not prove that every version, display mode, or computer will behave the same way. It does mean that an unrestricted result was not practical in this setup.&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%2Fzojedptegz8loztlb68f.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%2Fzojedptegz8loztlb68f.png" alt="Studio 3T showing a not responding message while reading documents from a MongoDB collection." width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Studio 3T became unresponsive while attempting to load 50,000 documents.&lt;/p&gt;

&lt;p&gt;If a client struggles, reduce both the number of documents and the number of fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.largeCollection.find(
  {},
  {
    _id: 1,
    company: 1,
    registered: 1
  }
).limit(1000)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is usually the better daily workflow. A large result may be useful for inspection or export, but it still consumes database resources, network bandwidth, memory, and rendering time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test 2: Comparing two MongoDB collections
&lt;/h3&gt;

&lt;p&gt;For this test, I used two controlled collections in the &lt;code&gt;QA_Edit&lt;/code&gt; database: &lt;code&gt;orders_compare_source&lt;/code&gt; and &lt;code&gt;orders_compare_target&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both collections started with 1,000 identical documents. I then modified 100 documents, removed 50, and added 50 in the target collection. I matched the documents by &lt;code&gt;_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;VisuaLeaf and Studio 3T both found 850 identical documents, 100 modified documents, 50 missing from the source, and 50 missing from the target.&lt;/p&gt;

&lt;p&gt;A useful comparison must answer three questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Which documents exist on only one side?  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which fields changed inside matching documents?  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What will be inserted, updated, or deleted during synchronization?  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  VisuaLeaf
&lt;/h3&gt;

&lt;p&gt;VisuaLeaf has a dedicated &lt;a href="https://visualeaf.com/features/collection-compare/" rel="noopener noreferrer"&gt;Collection Compare&lt;/a&gt; workflow for schema and data differences. It keeps the comparison next to the document, query, and data-operation tools.&lt;/p&gt;

&lt;p&gt;The important setup choice is the matching field. &lt;code&gt;_id&lt;/code&gt; works only if both collections preserve the same values. If an import regenerated them, use a stable key such as &lt;code&gt;customerId&lt;/code&gt;, &lt;code&gt;orderId&lt;/code&gt;, or &lt;code&gt;externalId&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiq7a0zy8xurbsmqnxhcl.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%2Fiq7a0zy8xurbsmqnxhcl.png" alt="VisuaLeaf comparison results for two MongoDB collections showing 850 identical documents, 100 modified, 50 missing in source, and 50 missing in target." width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VisuaLeaf found 850 identical, 100 modified, and 50 documents missing from each collection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Studio 3T
&lt;/h3&gt;

&lt;p&gt;Studio 3T provides the most detailed comparison controls of the three. Its &lt;a href="https://studio3t.com/knowledge-base/articles/compare-mongodb-collections/" rel="noopener noreferrer"&gt;Data Compare &amp;amp; Sync&lt;/a&gt; supports collections on different databases or servers, document- and field-level differences, result export, and synchronization in either direction.&lt;/p&gt;

&lt;p&gt;Bi-directional synchronization is useful, but it increases the cost of a wrong choice. Decide which collection is the source of truth before applying 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%2Fsst1txnfatzh32wc7zwl.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%2Fsst1txnfatzh32wc7zwl.png" alt="Studio 3T MongoDB collection comparison showing 850 identical documents, 100 different, 50 without a source match, and 50 without a target match." width="800" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Studio 3T returned the same differences using &lt;code&gt;_id&lt;/code&gt; as the matching field.&lt;/p&gt;

&lt;h3&gt;
  
  
  MongoDB Compass
&lt;/h3&gt;

&lt;p&gt;Compass does not provide the same dedicated collection-diff workflow. You can still build part of the comparison with an aggregation.&lt;/p&gt;

&lt;p&gt;For example, this pipeline finds source documents without a matching &lt;code&gt;_id&lt;/code&gt; in the target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.orders_compare_source.aggregate([
  {
    $lookup: {
      from: "orders_compare_target",
      localField: "_id",
      foreignField: "_id",
      as: "target"
    }
  },
  {
    $match: {
      target: {
        $eq: []
      }
    }
  },
  {
  $count: "missingInTarget"
  }
  }
])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This finds missing matches, not every field-level change. It also assumes both collections are in the same database. Comparing data on different servers requires a script, a temporary copy, or another tool.&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%2Ffrss7hzgk6ctcpa765ul.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%2Ffrss7hzgk6ctcpa765ul.png" alt="MongoDB Compass pipeline showing 50 documents missing from orders_compare_target." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compass used an aggregation pipeline to find 50 source documents missing from the target.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 3: Automating Daily Orders
&lt;/h2&gt;

&lt;p&gt;Large collections make small mistakes more expensive.&lt;/p&gt;

&lt;p&gt;For this test, I used a daily orders JSON file.&lt;/p&gt;

&lt;p&gt;In Studio 3T, I imported the file into a &lt;code&gt;daily_orders&lt;/code&gt; collection. Studio 3T can also save and schedule tasks, so it works well when you want to repeat imports, exports, or other database 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%2Ffpjf7d4nhpa03nrp24j5.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%2Ffpjf7d4nhpa03nrp24j5.png" alt="Build a connected workflow: import to staging, then continue with the next task" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JSON import task: import a file into a collection&lt;/p&gt;

&lt;p&gt;In VisuaLeaf, I used &lt;a href="https://visualeaf.com/features/task-manager/" rel="noopener noreferrer"&gt;Task Manager&lt;/a&gt; to connect more than one step:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Import Daily Orders JSON → Add Orders to Main Collection → Export Sales Report&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcte0fhqvveg4r2p5x5nl.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%2Fcte0fhqvveg4r2p5x5nl.png" alt="VisuaLeaf can turn import, copy, and export steps into one connected workflow." width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VisuaLeaf lets you connect tasks into a workflow, not just run one import.&lt;/p&gt;

&lt;p&gt;The useful part is that tasks can have parent tasks. So the next task runs after the previous one is completed.&lt;/p&gt;

&lt;p&gt;This is helpful when the work is not just “import this file.” In a real workflow, you may need to import data, map fields, move it into the main collection, mask sensitive data, and export a report after that.&lt;/p&gt;

&lt;p&gt;For example, field mapping matters because &lt;code&gt;orderedAt&lt;/code&gt; should be mapped to &lt;code&gt;createdAt&lt;/code&gt; as a MongoDB Date, and values like email or phone numbers may need data masking before export.&lt;/p&gt;

&lt;p&gt;So for me, Studio 3T is strong for saving and scheduling database tasks. VisuaLeaf is easier when I want to see a connected workflow in one place and control the order of the steps.&lt;/p&gt;

&lt;p&gt;Compass is different. It is great for interactive work, but recurring workflows usually need something outside the desktop app, like a script, cron, Windows Task Scheduler, CI, or an Atlas service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 4: Checking the Query Before Blaming the Client
&lt;/h2&gt;

&lt;p&gt;The first test measured how each tool handled a large result on screen.&lt;/p&gt;

&lt;p&gt;This test is different. Here, I wanted to check the work MongoDB was doing before the data even reached the client.&lt;/p&gt;

&lt;p&gt;I started with a query that had no supporting index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.largeCollection.find({
  company: "ZENSOR"
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part was the explain plan.&lt;/p&gt;

&lt;p&gt;I checked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scan stage in the winning plan: &lt;code&gt;COLLSCAN&lt;/code&gt; or &lt;code&gt;IXSCAN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;totalDocsExamined&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;totalKeysExamined&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nReturned&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;execution time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the query uses &lt;code&gt;COLLSCAN&lt;/code&gt;, MongoDB has to scan the collection to find matching documents. That means the slow part is not always the GUI. Sometimes the database is simply doing too much work.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;COLLSCAN&lt;/code&gt; is not automatically a problem. But in this case, scanning 50,844 documents to return only 51 showed that the query could benefit from an index.&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%2F6tldf2vqff2bhxa8vown.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%2F6tldf2vqff2bhxa8vown.png" alt="VisuaLeaf Query Profiler showing a collection scan with 50,844 documents examined and 51 returned." width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VisuaLeaf detected a &lt;code&gt;COLLSCAN&lt;/code&gt;, examining 50,844 documents to return 51.&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%2Fiee01pq7102ob5althrg.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%2Fiee01pq7102ob5althrg.png" alt="Studio 3T Visual Explain showing a collection scan with 50,844 documents examined and 51 returned." width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Studio 3T reported a collection scan across 50,844 documents for 51 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%2Ftsosejsdllswyi86leny.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%2Ftsosejsdllswyi86leny.png" alt="MongoDB Compass Explain Plan showing a collection scan with 50,844 documents examined and 51 returned." width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compass used a &lt;code&gt;COLLSCAN&lt;/code&gt;, examining all 50,844 documents to find 51 matches.&lt;/p&gt;

&lt;p&gt;After that, I created an index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.largeCollection.createIndex({
  company: 1
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I ran the same explain operation again.&lt;/p&gt;

&lt;p&gt;A lower execution time is useful, but the stronger evidence is that the winning plan now contains an &lt;code&gt;IXSCAN&lt;/code&gt;. In this test, &lt;code&gt;totalDocsExamined&lt;/code&gt; dropped from 50,844 to 51, matching the 51 returned documents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://visualeaf.com/features/query-profiler/" rel="noopener noreferrer"&gt;VisuaLeaf’s Query Profiler&lt;/a&gt; is useful here because it brings slow queries, execution plans, index usage, scanned documents, returned documents, and optimization hints into 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%2Flnau13lp7bkxu91xst07.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%2Flnau13lp7bkxu91xst07.png" alt="VisuaLeaf Query Profiler showing the company index with 51 documents and 51 index keys examined." width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After adding the &lt;code&gt;company_1&lt;/code&gt; index, VisuaLeaf examined 51 documents and 51 index keys.&lt;/p&gt;

&lt;p&gt;Studio 3T has the deepest performance tools in this comparison, with Query Profiler, Visual Explain, and Index Manager.&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%2Fgog4gnfsvko3tdj4gdag.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%2Fgog4gnfsvko3tdj4gdag.png" alt="Studio 3T Visual Explain showing an index scan using company_1 and examining 51 documents." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;company_1&lt;/code&gt; index, Studio 3T used an index scan and examined 51 documents.&lt;/p&gt;

&lt;p&gt;Compass also has Explain Plan, which works well when you already know which query you want to inspect.&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%2Fsxogwnyk27lb4qg0j8tm.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%2Fsxogwnyk27lb4qg0j8tm.png" alt="MongoDB Compass Explain Plan showing an index scan with 51 documents and 51 index keys examined." width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After indexing &lt;code&gt;company&lt;/code&gt;, Compass changed to &lt;code&gt;IXSCAN&lt;/code&gt; and examined only 51 documents.&lt;/p&gt;

&lt;p&gt;For this test, the main point was simple: before blaming the client, check if MongoDB is scanning too much data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which client fits which workflow?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If you mainly need to…&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Open and work with a large continuous result&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VisuaLeaf&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;It loaded 50,000 documents in 13.481 seconds and remained usable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compare two collections visually&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VisuaLeaf&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;It clearly separated identical, modified, and missing documents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automate multi-step data workflows&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VisuaLeaf&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Import, copy, export, and scheduling can be managed in one workflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find inefficient queries in the same workspace&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VisuaLeaf&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Query Profiler combines plans, index usage, scanned documents, and optimization hints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browse documents in small pages with a free official client&lt;/td&gt;
&lt;td&gt;MongoDB Compass&lt;/td&gt;
&lt;td&gt;Pagination keeps browsing controlled and predictable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access advanced synchronization and administration controls&lt;/td&gt;
&lt;td&gt;Studio 3T&lt;/td&gt;
&lt;td&gt;It provides more granular diff, sync, and performance options&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is no single client for every MongoDB job. Compass is a good option for controlled, paginated browsing, while Studio 3T offers advanced administration and synchronization controls. But for everyday work with large results, collection comparisons, automated tasks, and query analysis, &lt;a href="https://visualeaf.com" rel="noopener noreferrer"&gt;VisuaLeaf&lt;/a&gt; provides the most complete workflow in one place.&lt;/p&gt;

&lt;p&gt;Choose the client around the operation that costs you time, not the longest feature list.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>javascript</category>
      <category>database</category>
      <category>software</category>
    </item>
    <item>
      <title>How to Copy and Sync a MongoDB Collection to PostgreSQL</title>
      <dc:creator>VisuaLeaf</dc:creator>
      <pubDate>Tue, 28 Jul 2026 07:46:26 +0000</pubDate>
      <link>https://dev.to/visualeaf/how-to-copy-and-sync-a-mongodb-collection-to-postgresql-1of7</link>
      <guid>https://dev.to/visualeaf/how-to-copy-and-sync-a-mongodb-collection-to-postgresql-1of7</guid>
      <description>&lt;p&gt;I tested a MongoDB-to-PostgreSQL sync with a &lt;code&gt;visits&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;At first, I thought the hard part would be the sync itself. It was not. The harder part was making PostgreSQL understand the MongoDB document shape.&lt;/p&gt;

&lt;p&gt;MongoDB lets one document contain strings, dates, nested objects, arrays, and an &lt;code&gt;_id&lt;/code&gt;. PostgreSQL wants fixed columns, clear data types, and a primary key.&lt;/p&gt;

&lt;p&gt;So before running the sync, I had to decide what the PostgreSQL table should look like.&lt;/p&gt;

&lt;p&gt;For this test, I used &lt;a href="https://visualeaf.com/features/mongosync/" rel="noopener noreferrer"&gt;VisuaLeaf Mongo Sync.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used it because I wanted to set up the workflow visually: source collection, target PostgreSQL table, field mapping, and sync status. I still had to create the PostgreSQL table and check the mapping carefully, but I did not have to write a custom sync script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Collection
&lt;/h2&gt;

&lt;p&gt;The source was:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;database_compare_demo.visits&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Each MongoDB document had simple fields like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visitId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visitDate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visitReason&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also had nested fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;patient&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;doctor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;symptoms&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prescriptions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;invoice&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;labResults&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visitDetails&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vitals&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clinic&lt;/code&gt;&lt;/li&gt;
&lt;/ul&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%2Fl8hcpn2ccn6ad1z3w82i.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%2Fl8hcpn2ccn6ad1z3w82i.png" alt="VisuaLeaf showing the MongoDB visits collection in a local replica set." width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB &lt;code&gt;visits&lt;/code&gt; collection with nested patient, doctor, lab results, and vitals data.&lt;/p&gt;

&lt;p&gt;This is where the mapping matters. If you try to force every nested MongoDB field into separate SQL columns too early, the setup gets messy fast.&lt;/p&gt;

&lt;p&gt;For this test, I used a PostgreSQL landing table.&lt;/p&gt;

&lt;h2&gt;
  
  
  PostgreSQL Table
&lt;/h2&gt;

&lt;p&gt;I created one table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mongo_visits_sync&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;mongo_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"visit_id"&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"visit_date"&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"visit_reason"&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="n"&gt;patient&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;doctor&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;symptoms&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prescriptions&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;invoice&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"lab_results"&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;"visit_details"&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vitals&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;clinic&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I kept the simple fields as normal columns.&lt;/p&gt;

&lt;p&gt;I stored the nested MongoDB objects and arrays as &lt;code&gt;JSONB&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This was easier to test, and it kept the original document structure instead of flattening everything too early.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;mongo_id&lt;/code&gt; Is Important
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://visualeaf.com/database/postgresql/" rel="noopener noreferrer"&gt;PostgreSQL table&lt;/a&gt; needs a primary key.&lt;/p&gt;

&lt;p&gt;In this setup, MongoDB &lt;code&gt;_id&lt;/code&gt; maps to PostgreSQL &lt;code&gt;mongo_id&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_id -&amp;gt; mongo_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this, the sync cannot safely update existing rows.&lt;/p&gt;

&lt;p&gt;One error I hit was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SQL target has no key columns — cannot upsert idempotently
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means PostgreSQL did not have a usable key for the sync job.&lt;/p&gt;

&lt;p&gt;The fix was to create &lt;code&gt;mongo_id&lt;/code&gt; as the primary key and map MongoDB &lt;code&gt;_id&lt;/code&gt; to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Field Mapping and Data Types
&lt;/h2&gt;

&lt;p&gt;In VisuaLeaf, the &lt;a href="https://visualeaf.com/docs/mongosync" rel="noopener noreferrer"&gt;mapping shows&lt;/a&gt; the MongoDB fields with simple source types like &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Object&lt;/code&gt;, and &lt;code&gt;Array&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That matters because not every MongoDB field should become a normal text column in PostgreSQL.&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%2Fnn7djc7733kh5pcy834r.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%2Fnn7djc7733kh5pcy834r.png" alt="New transformation mapping screen in VisuaLeaf with Generate Field Mappings button." width="799" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating a new transformation mapping before generating the MongoDB to PostgreSQL fields.&lt;/p&gt;

&lt;p&gt;For this test, I used this logic:&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%2Fm567sg8wo440fq8s0t1m.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%2Fm567sg8wo440fq8s0t1m.png" alt="VisuaLeaf field mapping table for MongoDB to PostgreSQL sync." width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Field mapping from MongoDB fields to PostgreSQL columns, including objects and arrays.&lt;/p&gt;

&lt;p&gt;The simple string fields went into normal PostgreSQL text columns.&lt;/p&gt;

&lt;p&gt;The objects and arrays went into &lt;code&gt;JSONB&lt;/code&gt; columns.&lt;/p&gt;

&lt;p&gt;This was the important part. If I mapped an object or array into a normal text column, the sync would either fail or store the data in a way that is harder to query later.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;patient&lt;/code&gt; is an object, so I mapped it to a &lt;code&gt;JSONB&lt;/code&gt; column.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;symptoms&lt;/code&gt; is an array, so I also mapped it to &lt;code&gt;JSONB&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The main key was:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;_id -&amp;gt; mongo_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That gave PostgreSQL a stable primary key for updates and deletes during sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Error I Had With Column Names
&lt;/h2&gt;

&lt;p&gt;At first, my PostgreSQL table used names like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lab_results
visit_details
visit_reason
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the sync tried to insert into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;labResults
visitDetails
visitReason
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So PostgreSQL returned 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;ERROR: column "labResults" of relation "mongo_visits_sync" does not exist
&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%2F6donwbfxzdi6dt5v14k0.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%2F6donwbfxzdi6dt5v14k0.png" alt="VisuaLeaf Mongo Sync audit log showing a PostgreSQL column name mismatch error for labResults." width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sync failed because the MongoDB field &lt;code&gt;labResults&lt;/code&gt; did not match the PostgreSQL column &lt;code&gt;lab_results&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The problem was not PostgreSQL. The problem was the mismatch between the mapping and the real column names.&lt;/p&gt;

&lt;p&gt;You can fix this in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep snake_case in PostgreSQL and map each field manually.&lt;/li&gt;
&lt;li&gt;Use quoted camelCase column names in PostgreSQL.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Sync Setup
&lt;/h2&gt;

&lt;p&gt;The source MongoDB database was a replica set.&lt;/p&gt;

&lt;p&gt;That matters because continuous sync uses MongoDB change streams. Change streams work with replica sets and sharded clusters, not standalone MongoDB.&lt;/p&gt;

&lt;p&gt;The setup was:&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%2Fvueygds3b4eyuotmzz5p.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%2Fvueygds3b4eyuotmzz5p.png" alt="VisuaLeaf Mongo Sync rules screen mapping visits to a target table." width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mapping the MongoDB &lt;code&gt;visits&lt;/code&gt; collection to the PostgreSQL target table.&lt;/p&gt;

&lt;p&gt;I used Full sync because I wanted the first copy and the 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%2F4cudvrsz4z1w8ojv1i9n.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%2F4cudvrsz4z1w8ojv1i9n.png" alt="VisuaLeaf Mongo Sync review screen before launching the sync job." width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Final review before saving the MongoDB to PostgreSQL sync job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking the Initial Copy
&lt;/h2&gt;

&lt;p&gt;After running the sync, I checked the row count:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT COUNT(*) AS synced_rows
FROM public.mongo_visits_sync;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I checked a few fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    "visit_id",
    status,
    "visit_date",
    patient -&amp;gt;&amp;gt; 'fullName' AS patient_name,
    doctor -&amp;gt;&amp;gt; 'fullName' AS doctor_name
FROM public.mongo_visits_sync;
&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%2F9dmq1h98l2053vohpdoy.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%2F9dmq1h98l2053vohpdoy.png" alt="PostgreSQL table in VisuaLeaf showing synced MongoDB visit rows." width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Synced MongoDB visit documents shown in the PostgreSQL target table.&lt;/p&gt;

&lt;p&gt;This confirmed that normal fields were copied into columns, and nested values were still queryable from &lt;code&gt;JSONB&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Insert, Update, and Delete
&lt;/h2&gt;

&lt;p&gt;The first copy is not enough to prove the sync works.&lt;/p&gt;

&lt;p&gt;So I tested changes from MongoDB too.&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%2Fw44x2yu0fkuglryshkzu.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%2Fw44x2yu0fkuglryshkzu.png" alt="VisuaLeaf Mongo Sync monitor showing live insert update and delete events." width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live sync monitor showing inserts, updates, deletes, and connection status.&lt;/p&gt;

&lt;p&gt;For the update test, I used:&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.updateOne(
  { visitId: "VIS-SYNC-TEST" },
  {
    $set: {
      status: "completed",
      "visitDetails.notes": "Updated after initial sync"
    }
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I checked PostgreSQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT
    "visit_id",
    status,
    "visit_details" -&amp;gt;&amp;gt; 'notes' AS notes
FROM public.mongo_visits_sync
WHERE "visit_id" = 'VIS-SYNC-TEST';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The updated status and note appeared in PostgreSQL.&lt;/p&gt;

&lt;p&gt;I also tested insert and delete. The new document appeared in PostgreSQL, and the deleted document was removed from the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Watch For
&lt;/h2&gt;

&lt;p&gt;The sync works, but the setup is not automatic magic.&lt;/p&gt;

&lt;p&gt;You still need to be careful with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;primary keys&lt;/li&gt;
&lt;li&gt;field mapping&lt;/li&gt;
&lt;li&gt;camelCase vs snake_case column names&lt;/li&gt;
&lt;li&gt;nested objects&lt;/li&gt;
&lt;li&gt;arrays&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JSONB&lt;/code&gt; fields&lt;/li&gt;
&lt;li&gt;unmapped MongoDB fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a first version, one PostgreSQL landing table is usually easier than trying to normalize everything.&lt;/p&gt;

&lt;p&gt;After the data is synced, you can decide if some fields should move into separate SQL tables later.&lt;/p&gt;

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

&lt;p&gt;This kind of sync is useful when MongoDB is where the app data lives, but PostgreSQL is better for reporting, SQL queries, dashboards, or sharing data with teams that work mostly in relational databases.&lt;/p&gt;

&lt;p&gt;The goal is not only to copy the collection once. The useful part is keeping PostgreSQL updated when documents are inserted, updated, or deleted in MongoDB.&lt;/p&gt;

&lt;p&gt;For this test, the cleanest setup was to store simple fields as normal PostgreSQL columns and keep nested objects and arrays as &lt;code&gt;JSONB&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once the primary key, column names, data types, and field mapping were correct, &lt;a href="https://visualeaf.com/features/mongosync/" rel="noopener noreferrer"&gt;VisuaLeaf Mongo Sync&lt;/a&gt; could handle the copy and the later changes without writing a custom sync script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to Sync MongoDB to Atlas Instead?
&lt;/h2&gt;

&lt;p&gt;If you want to copy a local MongoDB collection to Atlas and keep it in sync, I covered the full process in this detailed guide: &lt;a href="https://visualeaf.com/blog/copy-sync-local-mongodb-collection-to-atlas/" rel="noopener noreferrer"&gt;How to Copy a Local MongoDB Collection to Atlas—and Keep It in Sync.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>postgres</category>
      <category>database</category>
      <category>software</category>
    </item>
    <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>
  </channel>
</rss>
