Database

MongoDB Review 2025: The Document Database That Powers Modern Apps

SR
Suresh Reddy
March 8, 2025
16 min read

The Night Everything Broke

It was 2:47 AM on a Wednesday when my phone started buzzing. Not the gentle pulse of a text message -- the aggressive, repeating vibration that means PagerDuty, which means production, which means something has gone wrong in a way that affects actual humans trying to use our software. I fumbled for the screen. The alert was a cascade of database timeouts. Our PostgreSQL instance -- the one that had been "fine" for three years -- was choking on a schema migration that our backend team had deployed eight hours earlier.

The migration was supposed to add a new column to the orders table. Simple enough, except that our orders table had 47 million rows, and the ALTER TABLE command had been holding a lock for six hours. No reads. No writes. No orders processing. Our e-commerce platform was effectively a static webpage with a shopping cart that led nowhere.

By 4 AM, we had rolled back the migration, restarted the database, and watched the orders slowly trickle back in. By 6 AM, the post-incident Slack channel had 200 messages, a thread titled "we need to talk about our database," and a quietly furious CTO who wanted answers by the end of the week.

That was the week we started seriously looking at MongoDB.

Stage One: The Prototype (Weeks 1-3)

I want to be clear about something. We did not choose MongoDB because it was trendy or because someone read a blog post. We chose it because our specific problem -- a rapidly evolving product catalog where different product types had wildly different data structures -- was genuinely painful to model in relational tables. Shoes had sizes and colors. Electronics had specifications and compatibility matrices. Digital products had download links and license keys. In PostgreSQL, we had either one enormous table with dozens of nullable columns (most of them empty for any given row) or a sprawling constellation of joined tables that made simple queries feel like archaeology.

MongoDB's document model solved this elegantly. Each product was a document. A shoe document had shoe fields. An electronics document had electronics fields. They lived in the same collection but carried only the data that was relevant to them. No nulls. No joins. No schema migration when we added a new product type -- we just started inserting documents with new fields.

The prototype took three weeks. We modeled five product types, imported a subset of our catalog, and built a basic API on top of it using Node.js and the official MongoDB driver. Query performance was immediate and obvious: product page loads that had been averaging 120ms with the relational approach dropped to 8ms. Not because MongoDB is naturally faster -- it is not, for many query patterns -- but because we were retrieving one document instead of joining five tables.

Stage Two: The Migration (Weeks 4-10)

Migrating to MongoDB Atlas was the decision that turned the prototype into a production commitment. Atlas is MongoDB's managed cloud service, and the reason our CTO approved the migration is that nobody on our team wanted to operate database infrastructure ever again. The 2:47 AM page that started this whole story was partly a database problem and partly an operations problem -- we did not have the expertise to run a highly available, automatically backed-up, performance-monitored database. Atlas handles all of that.

Setting up an Atlas cluster took about fifteen minutes. Pick a cloud provider (we chose AWS), pick a region, pick an instance size, and Atlas provisions a three-node replica set with automated backups, monitoring, and alerting. The free M0 tier -- 512MB of storage on a shared cluster -- is where we started testing. For prototype work and learning, it is genuinely free and genuinely useful. The jump to production meant moving to an M10 dedicated cluster at $57 a month, which gave us dedicated resources, custom backup schedules, and the Performance Advisor that analyzes slow queries and recommends indexes.

The data migration itself was handled by a custom script that read from PostgreSQL, transformed the relational data into documents, and wrote to MongoDB. We ran both databases in parallel for two weeks, writing to both and reading from Postgres while validating that MongoDB's responses matched. The dual-write period caught several data modeling issues we had not anticipated -- timestamps that needed different handling, array fields that occasionally exceeded the 16MB document size limit, and index strategies that looked good on paper but performed poorly under real traffic patterns.

Stage Three: Production and the Aggregation Revelation (Weeks 10-20)

MongoDB's aggregation framework is the feature that most surprised me. I expected basic group-by operations. What I found was a full data processing pipeline that eliminated our need for several scheduled ETL jobs. Let me give you a concrete example: we needed a daily report showing revenue by product category, broken down by region, with a seven-day moving average. In PostgreSQL, this was a stored procedure with three CTEs and a window function that took about four seconds to run. In MongoDB, it was a six-stage aggregation pipeline -- match, unwind, group, project, sort, merge -- that ran in 800 milliseconds and wrote the results directly to a reporting collection.

The $lookup stage gave us JOIN-like capabilities when we needed them, though I want to be honest: $lookup is slower than a real SQL JOIN and should be used sparingly. The document model's philosophy is to embed related data within a single document whenever possible, and $lookup is the escape hatch for when denormalization does not make sense. We used it for connecting orders to user profiles in analytical queries, and the performance was acceptable but not impressive.

Atlas Search, which brings Apache Lucene into MongoDB, replaced our standalone Elasticsearch instance. Product search queries -- including fuzzy matching, faceted filtering by category and price range, and relevance scoring -- ran directly against our MongoDB data without any synchronization layer. One less service to maintain. One less thing to break at 2:47 AM.

The Pricing Talk

Our CTO asked me to prepare a cost analysis for the executive meeting. What follows is roughly the conversation we had, reconstructed from my notes and colored by the anxiety of presenting a database migration bill to a room full of people who sign budgets.

"Walk me through the costs," she said.

"The Community Edition is free. SSPL-licensed. We could self-host it on our own infrastructure and pay nothing for the database software itself."

"But we are not doing that."

"No. We are using Atlas because the last time we self-hosted a database, I got paged at 3 AM and we lost six hours of orders. Atlas M10 dedicated clusters start at $57 a month. We are on an M30, which runs about $450 a month. That covers a three-node replica set, automated backups, monitoring, Performance Advisor, and the security posture that our compliance team requires."

"That seems reasonable."

"It is, for now. But I want to flag something: if our data grows beyond 100GB, we will need to upgrade to M40 or higher, which jumps to around $1,100 a month. And if we enable Atlas Search, there is an additional charge based on the search node size. Our current search workload would add about $200 a month."

"What were we paying for PostgreSQL hosting?"

"$380 a month on RDS. Plus $120 a month for the Elasticsearch instance. So about $500 total. The MongoDB Atlas bill, with search, will be about $650."

"So more expensive."

"By about $150 a month. But the Elasticsearch sync layer -- the one that broke twice last quarter -- is gone. The schema migration problem that caused the incident is structurally eliminated. And I am no longer the only person who knows how to operate the database, because Atlas operates itself."

She approved it.

There is also the serverless option on Atlas, where you pay per operation rather than per cluster. For applications with wildly variable traffic -- APIs that spike during business hours and go quiet at night -- serverless can be cheaper. But for our steady, predictable workload, the dedicated cluster was more cost-effective and more predictable.

What Actually Works Well

Strengths in Production

  • The document model genuinely eliminates schema migration pain -- adding fields is just writing documents with new fields
  • Atlas is the best managed database experience I have used: monitoring, backups, scaling, security all handled well
  • Aggregation pipelines replaced several ETL jobs and a separate analytics database
  • Atlas Search eliminated our need for standalone Elasticsearch, reducing operational surface area
  • Change streams enabled real-time inventory updates without polling the database
  • Driver ecosystem covers every language we use with APIs that feel native, not bolted on
  • Multi-document ACID transactions work reliably when we need cross-collection consistency

Where We Hit Walls

  • Denormalization means data duplication -- updating a product name requires updating it everywhere it is embedded
  • Atlas costs escalate faster than you expect when you start enabling search, backups, and cross-region replication
  • Complex aggregation pipelines are hard to debug -- there is no EXPLAIN equivalent that tells you which stage is slow
  • The 16MB document size limit bit us once with a product that had thousands of reviews embedded
  • Schema freedom is dangerous without discipline -- three months in, we found six different date formats in the same collection
  • $lookup performance is not a replacement for real JOINs -- relational data still belongs in a relational database

Stage Four: Scaling and Living With It

Six months in, our MongoDB deployment handles about 12,000 operations per second at peak, stores roughly 60GB of data across three collections, and has had zero unplanned downtime. The Atlas Performance Advisor has recommended seven indexes that we would not have thought of, each one eliminating a slow query that users were silently suffering through. The automated backup system has been tested twice -- both times, restoring to a point-in-time was straightforward and took about twenty minutes.

Change streams turned out to be more valuable than we expected. When a product's stock level changes, a change stream event triggers a serverless function that updates the cache, notifies the search index, and sends a webhook to our logistics partner. This event-driven pipeline replaced a polling job that ran every five minutes and still missed updates.

We have not needed sharding yet, and I hope we do not for a while. Sharding adds operational complexity that even Atlas cannot fully abstract away -- choosing a shard key, understanding chunk distribution, ensuring queries route to the right shard. For our data size and throughput, a well-provisioned replica set handles everything. The Atlas documentation is honest about this: do not shard until you have exhausted vertical scaling. We have not exhausted it.

Versus Postgres, Versus DynamoDB

People always ask: "Why not just use PostgreSQL with JSONB?" It is a fair question. Postgres 15 and 16 have excellent JSON support, and for many use cases, JSONB columns give you document-like flexibility within a relational framework. The answer, for us, was query language depth. Querying deeply nested JSONB in Postgres requires syntax that is verbose and brittle compared to MongoDB's native query language. Our aggregation pipelines, which process millions of documents through multi-stage transformations, would have been significantly harder to write and optimize in PostgreSQL. If your data is mostly relational with occasional semi-structured fields, PostgreSQL plus JSONB is probably the better bet. If your data is natively document-shaped and your queries are document-oriented, MongoDB earns its place.

DynamoDB came up in our evaluation because we are on AWS. It would have eliminated the Atlas bill entirely and given us virtually unlimited throughput scaling. But DynamoDB's single-table design, limited query patterns, and the upfront key design work it requires made it the wrong choice for our use case. Our product catalog needs rich, ad-hoc queries -- filter by multiple attributes, full-text search, range queries on price and date. DynamoDB is excellent when access patterns are known and fixed. Ours are not.

The Verdict

Our Verdict: 4.4 / 5

MongoDB solved a real problem for our team: the friction of modeling polymorphic data in rigid schemas, the pain of schema migrations on large tables, and the operational burden of running our own database infrastructure. Atlas turned a database into a service that mostly takes care of itself, and the aggregation framework, change streams, and Atlas Search have consolidated several separate tools into one platform.

The 4.4 rating is honest. The document model is powerful but demands discipline -- without schema validation and data governance, your collections will drift into chaos. Atlas pricing escalates in ways that can surprise you. And for genuinely relational data, MongoDB is not the answer -- use Postgres, use MySQL, use the right tool for the shape of your data. MongoDB is not a universal database. It is a document database, and for document-shaped problems, it is the best one available.

If you are building a new application with data that is naturally hierarchical, if your schemas evolve faster than your migration scripts can keep up with, or if you are tired of being paged at 3 AM because a database you do not know how to operate has decided to hold a lock on your largest table -- MongoDB Atlas is worth the migration. We did it. We would do it again.

Start with the free M0 tier. Model your data. Run your queries. See if the document model fits your thinking. If it does, everything else falls into place. If it does not, you will know within a week, and you will not have spent a dollar finding out.

Comments (3)