Grokking MongoDB
Vote

0% completed

​

MongoDB vs RDBMS

The Same Data in Both Models

Schema

Relationships and Joins

Transactions

Scaling and Replication

Consistency

Summary of the Differences

Should a customer's orders be stored inside the customer's record, or in a place of their own? A relational database management system (RDBMS) such as PostgreSQL or MySQL normally gives one answer, and MongoDB normally gives the other. Most of the differences between the two follow from this choice. We will therefore use one customer with two orders throughout.

The Same Data in Both Models

An RDBMS stores John Doe and his orders in two tables, customers and orders. Each order row contains a customerId column, called a foreign key, that points to a row in customers. To read John with his orders, a SQL query joins the two tables at read time. A join combines the matching rows into one result.

MongoDB normally stores the same information as one document, with the orders nested inside it. The orderCount field keeps the number of orders, and the relational design keeps it in a column of customers.

{ _id: 1, name: "John Doe", email: "john.doe@example.com", orderCount: 2, orders: [ { orderId: 101, total: 40 }, { orderId: 102, total: 15 } ] }
John Doe and his two orders stored as rows in two related tables and as one MongoDB document.
John Doe and his two orders stored as rows in two related tables and as one MongoDB document.

The left side keeps each order in a separate row, so an order can be read, changed, or reported on independently of its customer. The right side needs no join to show John's account page. However, a report across all orders must look inside every customer document. Neither layout is better in general, because the right choice depends on your most frequent requests.

The vocabulary of the two systems also corresponds closely. A table becomes a collection, a row becomes a document, and a column becomes a field.

A column is declared for a whole table, while a field belongs to each document.
A column is declared for a whole table, while a field belongs to each document.

The correspondence is not exact in one respect. Notice where the column names sit in the picture: a column is declared once for the whole table, so it exists for every row. A field exists only in the documents that contain it.

Schema

An RDBMS declares its columns and types in advance, and a change to them is an explicit change to the table. Every row follows the declared structure, which prevents many data errors. However, such a change must be planned for a large table in production.

MongoDB does not require any declaration. However, "schema-less" is not an accurate description, since you can add rules when you want them. For example, you can give the customers collection a rule that every document must have a name and an email. MongoDB then refuses a document for John that has no email, with the error Document failed validation (error code 121).

The real difference is that rules are required in an RDBMS and optional in MongoDB, and that you can apply MongoDB's rules to only some fields.

Relationships and Joins

An RDBMS expresses a relationship with a foreign key, and it can enforce that relationship by refusing an order whose customer does not exist. MongoDB does not enforce references between collections, so your application is responsible for keeping them valid.

MongoDB offers two ways to model a relationship. The first is the embedding shown above, where the orders are stored inside the customer's document. The second is a reference, which looks much like the relational design: orders go in their own collection, and each one stores the customer's _id, which is 1 for John.

A step of the aggregation framework called $lookup then joins the two collections at read time. Asked for customer 1, it returns John's document with an added orders list that contains the two order documents from the other collection.

The common statement that MongoDB has no joins is therefore false. It is true that $lookup is a left outer join within one database, and that SQL offers more kinds of join with a shorter syntax. An application that joins many collections in most of its requests is usually better served by an RDBMS.

Transactions

Suppose a new order must also increase John's orderCount. In the embedded design, both changes are in one document, and MongoDB always applies a change to a single document atomically, so no transaction is needed. One update adds order 103 to the orders list and raises orderCount to 3, and no reader can see one change without the other.

In the referenced design, the same work touches two collections, because one write adds the order and a second write raises the count. If the server failed between the two writes, the count would be wrong, so the writes belong in a transaction. MongoDB has supported multi-document ACID transactions on replica sets since version 4.0 and on sharded clusters since version 4.2. A server running without replication cannot run them.

The test of a transaction is what happens to both writes together. When we made both writes in a transaction and then canceled it, which is called an abort, John still had two orders and an orderCount of 2. When we repeated the same writes and confirmed them, which is called a commit, the number of orders and the orderCount both became 3.

The two systems differ in how central transactions are. An RDBMS is designed around them, and they are the normal way to change related rows. In MongoDB, the documentation describes them as having a greater performance cost than single-document writes. By default, a transaction that runs for more than 60 seconds is also aborted. A MongoDB design therefore tries to place data that changes together in one document, and uses transactions for the remaining cases.

Scaling and Replication

An RDBMS usually grows first by moving to a larger server, and it often adds read-only copies to handle more reads. Dividing data across several servers is possible, for example with Citus for PostgreSQL or Vitess for MySQL, but it often comes from an extension or a separate product.

MongoDB includes sharding, so a collection can be divided across several servers as a standard feature. This does not remove the work, since you must choose a good shard key. A query that does not use the key may have to ask every shard, meaning every server that holds part of the data.

Replication differs in a similar way. MongoDB includes automatic failover in every replica set. When the primary becomes unavailable, the remaining members elect a new one, typically within 12 seconds with default settings. No writes can complete until the election finishes. Relational systems also support replication, usually from one primary server to replicas, but automatic failover often requires additional configuration or tools.

Consistency

Both systems give you the same basic behavior when you read from the server that accepts writes: you see the latest accepted data. Both can also return old data when you read from a replica, because replicas copy changes after they happen.

For this reason, "MongoDB is eventually consistent and an RDBMS is strongly consistent" is not an accurate comparison. MongoDB reads from the primary by default, and old values appear only if you choose to read from secondaries. An RDBMS that sends reads to replicas behaves in the same way.

Summary of the Differences

FeatureMongoDBRDBMS
Data modelCollections of BSON documentsTables of rows and columns
SchemaFlexible; optional validation rulesDeclared in advance and enforced
RelationshipsEmbedded data or references with $lookup; references not enforcedForeign keys and joins
TransactionsSingle-document writes are atomic; multi-document ACID transactions availableMulti-row ACID transactions are the normal way to work
Query languageMongoDB Query Language (MQL) and aggregation pipelinesSQL, with product differences
IndexesMany types, including indexes on arrays, on text, and on locationsDepends on product; sorted tree indexes are standard
Horizontal scalingBuilt-in shardingUsually by extension or separate product
ReplicationBuilt-in replica sets with automatic failoverSupported; failover often needs extra tools
Default readsFrom the primaryFrom the server you connect to
Good fitVaried data read as a unit, large data sets, device data, real-time analyticsMany relationships, flexible reports, business systems such as accounting and customer records

The boundary between the two is also less sharp than this table suggests. For example, PostgreSQL has a JSONB column type that stores documents inside a table. A useful way to decide is to write down your most frequent requests and sketch the data for them in both models, then choose the one where those requests are simplest.

Reading Progress

0%


Vote for new content

On This Page

The Same Data in Both Models

Schema

Relationships and Joins

Transactions

Scaling and Replication

Consistency

Summary of the Differences