Free — no signup required

Document Databases: Flexibility First

3 min read

Thinking in Objects

When you build an application, you think in objects: a User has a name, an email, a list of addresses, and a set of preferences. In a relational database, you must decompose this object across multiple tables (users, addresses, user_preferences) and reassemble it with JOIN queries every time you need it. This impedance mismatch between how developers think and how RDBMS store data is a constant source of friction.

Document Databases eliminate this mismatch by letting you store the entire object as a single, self-contained document — typically in JSON or a binary variant. The document is the unit of storage, retrieval, and update.

{
  "_id": "user_8472",
  "name": "Priya Sharma",
  "email": "[email protected]",
  "addresses": [
    { "type": "home", "city": "Mumbai", "zip": "400001" },
    { "type": "work", "city": "Pune", "zip": "411001" }
  ],
  "preferences": {
    "newsletter": true,
    "theme": "dark"
  },
  "linkedin_profile": "https://linkedin.com/in/priya"
}

A different user document in the same collection might have no linkedin_profile field at all, or might have a github_profile field that Priya's document lacks. This is schema flexibility: documents in the same collection do not need to share an identical structure.

The Champion: MongoDB

MongoDB is the dominant document database. Documents are stored in BSON (Binary JSON), which supports additional data types beyond standard JSON (like native date and binary types). Documents are organized into collections (analogous to SQL tables, but without enforced schema).

MongoDB supports rich queries on nested fields without requiring joins:

// Find all users whose home city is Mumbai
db.users.find({ "addresses.type": "home", "addresses.city": "Mumbai" })

// Find users who have a linkedin_profile field
db.users.find({ "linkedin_profile": { $exists: true } })

// Aggregation: count users by city
db.users.aggregate([
  { $unwind: "$addresses" },
  { $group: { _id: "$addresses.city", count: { $sum: 1 } } }
])

Schema flexibility trade-offs: The freedom to store any shape of document is powerful during rapid development but dangerous at scale. Without discipline, collections become inconsistent — some documents have email, others have Email, others have neither. Production MongoDB deployments use schema validation (JSON Schema rules enforced by the database) to prevent this drift while retaining flexibility for intentional variation.

Common use cases:
- Content management systems (articles, pages with varying metadata)
- Product catalogs (laptops have CPU specs; t-shirts have sizes and colors)
- User profiles with optional fields
- Event logging where event types have different payloads

Interview Tip

A common interview question: "When would you choose MongoDB over PostgreSQL?" The answer is not "when you need NoSQL." The correct answer focuses on specific drivers: (1) your data model varies significantly between records and changes frequently, making schema migrations costly; (2) your access pattern is almost always "fetch the whole object by ID" with no need for complex cross-entity joins; (3) you need to scale writes horizontally across shards. If you need strong ACID transactions across multiple entities, PostgreSQL's JSONB column type often gives you document-like flexibility without sacrificing relational guarantees.

Key Point: Document databases excel when your data structure evolves frequently or varies significantly between records. However, they are not a substitute for relational databases when your workload requires complex multi-entity transactions or ad-hoc analytical queries across many fields. MongoDB added multi-document ACID transactions in version 4.0, but they come with performance overhead — design your document model to avoid needing them.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free