NoSQL Databases: Architecture, Data Models, and Practical Use
Understand why NoSQL databases emerged and how their architectures differ from relational systems. This tutorial explores document, key-value, wide-column, and graph databases; data modeling; partitioning; sharding; replication; consistency; CAP; transactions; caching; CQRS; microservices; and polyglot persistence. It concludes with practical architecture decisions for ownership, data flow, scaling, performance, and failure scenarios.
Lesson 4: Document Databases
We can now begin examining the major NoSQL data models, starting with document databases. This lesson introduces the document model and explains how JSON-like documents, collections, embedded data, references, and flexible schemas change the way applications store and retrieve information. MongoDB will be used as the primary example so that the concepts can be connected to a real technology.
What Is a Document Database?
A document database is a NoSQL database that stores information as documents rather than rows in relational tables. A document usually represents a complete business object or aggregate, and its structure can contain nested objects and arrays. MongoDB is one of the most widely used examples of a document database.
Consider an online learning platform. A course might contain its title, description, instructor information, categories, and lessons. In a relational database, this information might be distributed across several tables. In MongoDB, much of it can potentially be represented as one document.
{
"courseId": 101,
"title": "ASP.NET Core Fundamentals",
"instructor": {
"name": "John Smith",
"email": "john@example.com"
},
"lessons": [
{
"title": "Dependency Injection",
"duration": 30
},
{
"title": "Middleware",
"duration": 25
}
]
}
The important architectural idea is that a document can closely resemble the object that the application works with. This can reduce the impedance mismatch between application objects and database structures.
JSON and BSON
Document databases commonly use a JSON-like representation. MongoDB internally uses BSON, which means Binary JSON. BSON supports JSON-like structures while also providing additional data types such as dates, binary data, and specific numeric types.
A C# application might work with a class such as:
public class Course
{
public string Id { get; set; }
public string Title { get; set; }
public Instructor Instructor { get; set; }
public List<Lesson> Lessons { get; set; }
}
The MongoDB .NET Driver can map this object to a MongoDB document. This makes MongoDB particularly natural for applications built around object-oriented domain models.
Collections
MongoDB organizes documents into collections. A collection is roughly comparable to a table in a relational database, although the concepts are not identical.
For example, an online learning platform could contain collections such as:
Courses
Students
Enrollments
Reviews
Documents inside the same collection do not necessarily need to have exactly the same structure. This is different from a traditional SQL table, where the database normally expects rows to conform to a defined schema.
Embedded Documents
One of the most important features of document databases is the ability to embed related data inside a document.
For example, instead of having separate Courses and Lessons tables, a course can contain its lessons directly:
{
"courseId": 101,
"title": "C# Fundamentals",
"lessons": [
{ "title": "Classes", "duration": 20 },
{ "title": "Interfaces", "duration": 25 }
]
}
This is useful when the embedded information belongs strongly to the parent object and is normally retrieved together with it. If the application almost always loads a course together with its lessons, embedding can provide a very efficient access pattern.
However, embedding is not always appropriate. If millions of students independently reference the same instructor, embedding the instructor inside every course could create excessive duplication and make updates difficult.
References
Instead of embedding data, a document can store a reference to another document.
For example:
{
"courseId": 101,
"title": "C# Fundamentals",
"instructorId": "I100"
}
The instructor can then exist separately in an Instructors collection.
References are useful when the related entity is large, frequently updated, shared by many documents, or has an independent lifecycle. The trade-off is that retrieving the complete information may require additional database operations.
Therefore, document modeling commonly involves deciding between embedding and referencing.
Flexible Schemas
Document databases are often described as schema-flexible. This means that documents in a collection can evolve without requiring the same kind of table migration normally associated with relational databases.
For example, an older product document might contain:
{
"name": "Laptop",
"price": 1200
}
A newer version might contain:
{
"name": "Laptop",
"price": 1200,
"brand": "Dell",
"screenSize": 15.6
}
This flexibility is valuable when different types of entities have different attributes or when requirements change frequently. However, flexibility can become a problem if it is not controlled. Poorly managed documents can eventually contain several incompatible versions of the same concept.
For production systems, schema validation, application validation, versioning, and migration strategies may still be necessary. Schema flexibility does not mean schema discipline is unnecessary.
Querying Documents
MongoDB provides a query language designed around documents. For example, we could find courses whose title contains a particular value:
db.courses.find({
title: "C# Fundamentals"
})
We can also query nested fields:
db.courses.find({
"instructor.name": "John Smith"
})
Arrays can also be queried:
db.courses.find({
"lessons.title": "Middleware"
})
MongoDB also provides an aggregation pipeline for more complex operations such as filtering, grouping, sorting, and calculating results. Indexes can be created to improve frequently used queries.
The important architectural point is that document databases are not simply storage systems for JSON. They provide querying and indexing capabilities designed around the document data model.
When Document Databases Are a Good Choice
Document databases are particularly useful when the application's data naturally forms aggregates or hierarchical objects. Product catalogs, content management systems, user profiles, course catalogs, configuration data, and many REST API workloads are good examples.
They are also useful when different records have varying attributes or when the application needs to evolve its data structure quickly. A document model can also work well when most operations retrieve an entire aggregate rather than joining many independent entities.
For example, an e-commerce product catalog may contain books, laptops, clothing, and furniture. Each category can have different attributes. A document model can represent these differences naturally without creating a large collection of nullable relational columns.
When a Document Database May Not Be the Best Choice
A document database may be less suitable when the application depends heavily on complex relationships, extensive joins, strict referential integrity, or large multi-entity transactions.
Consider a banking system containing accounts, transactions, customers, transfers, and regulatory records. The relationships and transactional requirements may make PostgreSQL or SQL Server a more natural foundation.
The decision should therefore be based on the application's data relationships, access patterns, consistency requirements, and transaction boundaries, rather than simply choosing MongoDB because it is classified as NoSQL.
Introduction to MongoDB
MongoDB is a document-oriented database designed around BSON documents. A typical architecture can contain an application, MongoDB drivers, a MongoDB cluster, replica sets, and optionally sharding for distributing data across multiple nodes.
A .NET application can connect using the official MongoDB driver:
var client = new MongoClient(connectionString);
var database = client.GetDatabase("LearningPlatform");
var courses = database.GetCollection<Course>("Courses");
var course = await courses
.Find(x => x.Title == "C# Fundamentals")
.FirstOrDefaultAsync();
This example shows an important characteristic of document databases: the application can work with a domain object while the database stores a document representation of that object.
Architectural Perspective
The most important concept in document databases is not JSON itself. It is the idea of designing data around the way the application uses it. You need to decide which information belongs together, which information should be embedded, which information should be referenced, and which queries need to be fast.
As we move into more advanced NoSQL topics, this idea will become increasingly important. MongoDB and other document databases provide flexibility and scalability, but good performance depends heavily on thoughtful data modeling.
The key idea is that a document database stores related information in document-shaped aggregates and gives architects greater flexibility in how data is structured. Its main strength is allowing the data model to closely match application access patterns, while its main challenge is deciding when to embed, reference, duplicate, or separate data.