MongoDB · Beginner to Advanced · C# and .NET Integration
MongoDB: Complete Developer Learning Guide
Learn MongoDB from database fundamentals to advanced concepts, including document modelling, CRUD operations, aggregation, indexing, transactions, scalability, and practical integration with C# and ASP.NET Core Web API.
MongoDB is a document-oriented NoSQL database designed to store and manage data in flexible, JSON-like documents. Unlike traditional relational databases, which organize information primarily into tables and rows, MongoDB stores information in collections and documents.
Modern applications often work with complex, nested, and evolving data structures. MongoDB provides a document model that allows developers to represent application data naturally, while supporting indexing, aggregation, transactions, replication, and horizontal scaling.
For .NET developers, MongoDB can be integrated into applications using the official MongoDB .NET/C# Driver. This allows developers to work with strongly typed C# classes, asynchronous database operations, LINQ queries, and ASP.NET Core dependency injection.
Learning roadmap
- Introduction to MongoDB
- SQL Server vs MongoDB
- MongoDB architecture
- BSON and document structure
- Installation and environment
- MongoDB Shell and Compass
- CRUD operations
- Query operators and projections
- Document modelling
- Relationships and references
- Schema validation
- Indexes and optimization
- Aggregation pipeline
- Transactions and atomicity
- Replication and high availability
- Sharding and scaling
- Security
- MongoDB with C# and .NET
- MongoDB .NET/C# Driver
- ASP.NET Core integration
- Repository and service patterns
- LINQ and strongly typed queries
- BSON serialization
- Performance and best practices
- Advanced MongoDB capabilities
- Backup, monitoring and deployment
- Learning and practice roadmap
1. Introduction to MongoDB
What is MongoDB?
MongoDB is a NoSQL document database. It stores data in BSON documents, which represent structured information using fields and values.
MongoDB is designed for applications that need flexible data structures, efficient document queries, high availability, and horizontal scalability.
What is a NoSQL database?
NoSQL refers to database systems that use data models other than the traditional relational table model. NoSQL databases are commonly used for flexible data structures, distributed workloads, and application-specific access patterns.
Types of NoSQL databases
| Database type | Data model | Examples |
|---|---|---|
| Document | JSON-like documents | MongoDB |
| Key-value | Key and associated value | Redis |
| Wide-column | Column families | Apache Cassandra |
| Graph | Nodes and relationships | Neo4j |
Why use MongoDB?
- Flexible document structures.
- Support for embedded documents and arrays.
- Powerful query and aggregation capabilities.
- Indexes for improving query performance.
- Replication for high availability.
- Sharding for horizontal scaling.
- Transactions for operations requiring multi-document consistency.
- Integration with modern application technologies, including .NET.
Where is MongoDB used?
- Content management systems.
- E-commerce applications.
- Product catalogues.
- Real-time applications.
- IoT and event data systems.
- Analytics and reporting workloads.
- Applications with evolving document structures.
2. SQL Server vs MongoDB
SQL Server and MongoDB solve different data-management problems. SQL Server is a relational database, while MongoDB uses a document-oriented data model.
| SQL Server | MongoDB |
|---|---|
| Relational database. | Document database. |
| Tables and rows. | Collections and documents. |
| Columns define table structure. | Documents contain fields and values. |
| SQL query language. | MongoDB Query API. |
| Primary keys. | _id field. |
| Foreign keys and joins. | Embedded documents, references and aggregation lookup. |
| Relational schema. | Flexible document schema with optional validation. |
| ACID transactions. | Single-document atomicity and multi-document ACID transactions. |
SQL Server and MongoDB terminology
| SQL Server | MongoDB |
|---|---|
| Database | Database |
| Table | Collection |
| Row | Document |
| Column | Field |
| Primary key | _id |
| Index | Index |
| Stored procedure | No direct equivalent; application logic and database commands serve different purposes. |
| JOIN | $lookup or application-side access. |
| GROUP BY | $group aggregation stage. |
When should you choose MongoDB?
- When application data is naturally represented as nested documents.
- When document structures evolve frequently.
- When a workload benefits from embedding related data.
- When horizontal scaling and distributed deployment are important.
When should you choose SQL Server?
- When relational integrity and foreign-key constraints are central.
- When complex relational joins are fundamental to the application.
- When reporting depends heavily on relational queries.
- When the application already relies on a mature relational data model.
3. MongoDB architecture
Database
A database is a logical container that stores collections and provides a namespace for related application data.
Collection
A collection is a group of MongoDB documents. It is broadly comparable to a table in a relational database, but documents in a collection do not have to contain identical fields.
Document
A document is the basic unit of information stored in MongoDB. It consists of field-value pairs and can contain nested objects and arrays.
{
"_id": 101,
"name": "Alex",
"department": "Development",
"salary": 60000
}
MongoDB architecture overview
- Application: Communicates with MongoDB using a database driver.
- MongoDB Server: Processes database operations.
- Database: Organizes application data.
- Collection: Groups related documents.
- Document: Stores individual records.
- Storage Engine: Manages how data is stored and retrieved.
MongoDB deployment types
| Deployment | Description |
|---|---|
| Community Server | Self-managed MongoDB deployment. |
| Enterprise Server | Commercial self-managed deployment with enterprise features. |
| MongoDB Atlas | Managed cloud database service. |
4. BSON and document structure
What is BSON?
BSON stands for Binary JSON. It is the binary-encoded document format used by MongoDB to store documents.
BSON supports JSON-like structures and additional data types such as ObjectId, Date, Decimal128, Binary, and Int64.
JSON vs BSON
| JSON | BSON |
|---|---|
| Text-based data interchange format. | Binary-encoded document format. |
| Commonly used for API communication. | Used for MongoDB document storage and communication. |
| Has a smaller set of native data types. | Supports additional BSON-specific types. |
| Human-readable. | Designed for structured binary representation. |
Common BSON data types
| Type | Description |
|---|---|
| String | Textual values. |
| Int32 | 32-bit integer. |
| Int64 | 64-bit integer. |
| Double | Floating-point number. |
| Decimal128 | 128-bit decimal value. |
| Boolean | True or false. |
| Date | Date/time represented as milliseconds since Unix epoch. |
| ObjectId | 12-byte BSON identifier. |
| Array | Ordered collection of values. |
| Object | Embedded document. |
| Null | Null value. |
Understanding ObjectId
MongoDB automatically generates an ObjectId for the _id field when an identifier is not supplied.
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "Alex",
"department": "Development"
}
ObjectId is a BSON identifier containing a timestamp component, random data, and a counter component. It is designed to provide a practical unique identifier, not a substitute for a guaranteed business sequence.
5. Installation and development environment
Tools required
- MongoDB Server: Runs the database engine.
- MongoDB Shell (mongosh): Interacts with MongoDB using commands.
- MongoDB Compass: Provides a graphical database interface.
- Visual Studio: Develops C# and ASP.NET Core applications.
- .NET SDK: Builds and runs .NET applications.
- MongoDB Atlas: Optional managed cloud deployment.
Installing MongoDB
Download the MongoDB Community Server for your operating system from the official website.
MongoDB Community Server Download
Install MongoDB Shell separately if it is not included in your installation package.
MongoDB Atlas
MongoDB Atlas is a managed cloud database platform. It allows developers to create and manage MongoDB deployments without maintaining the database server infrastructure themselves.
Connecting to a local MongoDB server
mongosh "mongodb://localhost:27017"
Connecting to MongoDB Atlas
Atlas provides a connection string for applications. The connection string includes deployment information and authentication details.
mongodb+srv://<username>:<password>@<cluster>.mongodb.net/
6. MongoDB Shell and Compass
MongoDB Shell
MongoDB Shell, commonly called mongosh, is an interactive command-line environment for executing MongoDB queries and administrative operations.
Basic commands
// Show databases
show dbs
// Create or switch database
use SkillsTutorials
// Show current database
db
// Show collections
show collections
// Create collection
db.createCollection("employees")
// Drop collection
db.employees.drop()
MongoDB Compass
MongoDB Compass is a graphical interface that allows developers to browse databases, inspect documents, create indexes, execute queries, and work with aggregation pipelines.
7. CRUD operations
CRUD stands for Create, Read, Update, and Delete. These are the fundamental operations used to manage application data.
Create: Insert documents
db.employees.insertOne({
name: "Alex",
department: "Development",
salary: 60000
})
Insert multiple documents
db.employees.insertMany([
{
name: "Sam",
department: "Testing",
salary: 45000
},
{
name: "John",
department: "Development",
salary: 70000
}
])
Read: Find documents
// Retrieve all employees
db.employees.find()
// Retrieve one employee
db.employees.findOne({
name: "Alex"
})
// Find employees in Development
db.employees.find({
department: "Development"
})
Update: Modify documents
db.employees.updateOne(
{ name: "Alex" },
{
$set: {
salary: 65000
}
}
)
Update multiple documents
db.employees.updateMany(
{ department: "Development" },
{
$set: {
isActive: true
}
}
)
Replace a document
db.employees.replaceOne(
{ name: "Sam" },
{
name: "Sam",
department: "Quality Assurance",
salary: 48000
}
)
Replacement operations replace the existing document contents, while preserving the immutable identifier.
Delete: Remove documents
// Delete one matching document
db.employees.deleteOne({
name: "Alex"
})
// Delete multiple matching documents
db.employees.deleteMany({
department: "Testing"
})
8. Query operators and projections
Comparison operators
| Operator | Purpose |
|---|---|
$eq | Equal to. |
$ne | Not equal to. |
$gt | Greater than. |
$gte | Greater than or equal to. |
$lt | Less than. |
$lte | Less than or equal to. |
$in | Matches any value in an array. |
$nin | Does not match values in an array. |
// Salary greater than 50000
db.employees.find({
salary: { $gt: 50000 }
})
// Salary between 40000 and 70000
db.employees.find({
salary: {
$gte: 40000,
$lte: 70000
}
})
// Department in a list
db.employees.find({
department: {
$in: ["Development", "Testing"]
}
})
Logical operators
// AND
db.employees.find({
department: "Development",
salary: { $gt: 50000 }
})
// OR
db.employees.find({
$or: [
{ department: "Development" },
{ salary: { $gt: 70000 } }
]
})
// NOT
db.employees.find({
salary: { $not: { $gt: 50000 } }
})
Field operators
// Check whether a field exists
db.employees.find({
email: { $exists: true }
})
// Check the field type
db.employees.find({
salary: { $type: "number" }
})
Projection
Projection controls which fields are returned from a query.
// Include name and department
db.employees.find(
{},
{
name: 1,
department: 1,
_id: 0
}
)
Sorting, limiting and skipping
// Ascending
db.employees.find().sort({
salary: 1
})
// Descending
db.employees.find().sort({
salary: -1
})
// Return only 5 documents
db.employees.find().limit(5)
// Skip first 5 documents
db.employees.find().skip(5)
// Count matching documents
db.employees.countDocuments({
department: "Development"
})
9. Document modelling and schema design
Data modelling defines how information should be organized within MongoDB documents and collections.
Embedded documents
An embedded document stores related information inside the parent document.
{
"_id": 101,
"name": "Alex",
"department": {
"name": "Development",
"location": "Delhi"
},
"skills": [
"C#",
"ASP.NET Core",
"MongoDB"
]
}
Embedded documents are useful when related information is commonly retrieved together and fits within MongoDB's document size limits.
Advantages of embedding
- Related data can be retrieved in one document query.
- Single-document updates are atomic.
- Reduces the need for multiple database operations.
- Represents hierarchical data naturally.
Disadvantages of embedding
- Documents can grow excessively.
- Frequently changing duplicated data can become difficult to maintain.
- Large arrays can create performance challenges.
Designing a document
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"orderNumber": "ORD-1001",
"customer": {
"customerId": 101,
"name": "Alex"
},
"items": [
{
"productId": 501,
"productName": "Laptop",
"quantity": 1,
"price": 50000
},
{
"productId": 502,
"productName": "Mouse",
"quantity": 2,
"price": 500
}
],
"orderDate": ISODate("2026-11-14T00:00:00Z"),
"status": "Confirmed"
}
This structure allows an order and its associated items to be retrieved together.
10. Relationships and references
MongoDB supports relationships through embedded documents and references. The appropriate approach depends on data access patterns, update frequency, and consistency requirements.
One-to-one relationship
A user and their profile can be represented as an embedded document.
{
"_id": 101,
"name": "Alex",
"profile": {
"city": "Delhi",
"country": "India"
}
}
One-to-many relationship
A customer can have multiple orders. When orders are independently queried and can grow significantly, keeping them in a separate collection may be more appropriate.
// customers collection
{
"_id": 101,
"name": "Alex"
}
// orders collection
{
"_id": 1001,
"customerId": 101,
"totalAmount": 50000
}
Many-to-many relationship
Employees and projects can have a many-to-many relationship.
// employees collection
{
"_id": 101,
"name": "Alex",
"projectIds": [501, 502]
}
// projects collection
{
"_id": 501,
"name": "RFP Automation"
}
Using $lookup
The $lookup aggregation stage performs a left outer join between collections.
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customerDetails"
}
}
])
11. Schema validation
MongoDB provides a flexible schema, but flexible does not mean that every document must be unstructured. Schema validation allows developers to enforce rules on document fields.
Creating a collection with validation
db.createCollection("products", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "price"],
properties: {
name: {
bsonType: "string"
},
price: {
bsonType: "number",
minimum: 0
},
isActive: {
bsonType: "bool"
}
}
}
}
})
Validation levels
- strict: Applies validation to all inserts and updates by default.
- moderate: Applies validation to documents that already satisfy the validator and to new inserts.
Validation actions
- error: Rejects writes that fail validation.
- warn: Allows the write but logs a validation warning.
12. Indexes and query optimization
Indexes improve query performance by allowing MongoDB to locate matching documents without scanning every document in a collection.
Single-field index
db.employees.createIndex({
department: 1
})
Descending index
db.employees.createIndex({
salary: -1
})
Compound index
A compound index includes multiple fields.
db.employees.createIndex({
department: 1,
salary: -1
})
Unique index
db.employees.createIndex(
{ email: 1 },
{ unique: true }
)
Text index
db.articles.createIndex({
title: "text",
description: "text"
})
TTL index
Time-to-live indexes automatically remove documents after a configured period based on a date field.
db.sessions.createIndex(
{ expiresAt: 1 },
{ expireAfterSeconds: 0 }
)
Geospatial index
Geospatial indexes support location-based queries.
db.places.createIndex({
location: "2dsphere"
})
Explain query execution
db.employees.find({
department: "Development"
}).explain("executionStats")
Index best practices
- Index fields frequently used in queries.
- Design compound indexes around real query patterns.
- Review execution statistics.
- Avoid unnecessary indexes.
- Monitor index storage and write overhead.
- Consider index selectivity and sort requirements.
13. Aggregation pipeline
The aggregation framework processes documents through a sequence of stages. Each stage transforms or filters the documents passed to the next stage.
Important aggregation stages
| Stage | Purpose |
|---|---|
$match | Filters documents. |
$project | Selects or transforms fields. |
$group | Groups documents and calculates values. |
$sort | Sorts documents. |
$limit | Limits results. |
$skip | Skips documents. |
$unwind | Deconstructs array fields. |
$lookup | Joins related collections. |
$count | Counts pipeline documents. |
$set | Adds or updates fields. |
Filtering with $match
db.employees.aggregate([
{
$match: {
department: "Development"
}
}
])
Grouping with $group
db.employees.aggregate([
{
$group: {
_id: "$department",
totalEmployees: {
$sum: 1
},
averageSalary: {
$avg: "$salary"
}
}
}
])
Sorting and limiting
db.employees.aggregate([
{
$sort: {
salary: -1
}
},
{
$limit: 5
}
])
Combining multiple stages
db.employees.aggregate([
{
$match: {
isActive: true
}
},
{
$group: {
_id: "$department",
employeeCount: {
$sum: 1
},
totalSalary: {
$sum: "$salary"
}
}
},
{
$sort: {
totalSalary: -1
}
}
])
This pipeline selects active employees, groups them by department, calculates employee counts and salary totals, and sorts the results.
14. Transactions and atomicity
What is atomicity?
Atomicity means an operation is completed entirely or not applied at all.
MongoDB guarantees atomicity at the single-document level. For operations requiring consistency across multiple documents, MongoDB also supports multi-document ACID transactions.
Single-document atomicity
Updating several fields inside one document is atomic at the document level.
db.accounts.updateOne(
{ _id: 101 },
{
$inc: {
balance: -500
}
}
)
Multi-document transactions
Transactions group multiple database operations into one logical unit. They can be committed together or rolled back.
When should you use transactions?
- When multiple documents must change consistently.
- When multiple collections participate in one business operation.
- When application requirements demand atomic changes across documents.
15. Replication and high availability
Replication maintains multiple copies of data across MongoDB servers. A replica set provides redundancy and supports automatic failover.
Replica set members
- Primary: Receives writes and coordinates replication.
- Secondary: Replicates data from the primary and can serve eligible reads.
- Arbiter: Participates in elections but does not store data.
How replication works
- The primary receives a write operation.
- The operation is recorded in the replication log (oplog).
- Secondaries replicate the changes.
- Replica set members participate in elections when the primary becomes unavailable.
- An eligible secondary can become the new primary.
16. Sharding and horizontal scaling
Sharding distributes data across multiple servers to support large datasets and high-throughput workloads.
What is horizontal scaling?
Horizontal scaling increases capacity by adding additional servers rather than relying only on increasing the resources of one server.
Sharding components
| Component | Responsibility |
|---|---|
| Shard | Stores a portion of the sharded data. |
| Config servers | Store cluster metadata and configuration. |
| Mongos | Routes client requests to the appropriate shards. |
| Shard key | Determines how data is distributed. |
Shard key selection
Shard key design is an important architectural decision. A suitable shard key should consider data distribution, query targeting, write patterns, and expected growth.
Advantages of sharding
- Distributes data across multiple machines.
- Supports larger datasets.
- Can increase write and read capacity.
- Allows workload distribution.
17. MongoDB security
Authentication
Authentication verifies the identity of a database user or application.
Authorization and RBAC
MongoDB uses role-based access control to assign privileges to database users.
Important security practices
- Enable authentication.
- Create separate users for different applications and responsibilities.
- Follow the principle of least privilege.
- Use TLS for protected network communication.
- Restrict network access.
- Store connection strings securely.
- Use appropriate encryption and backup protections.
- Monitor authentication and database activity.
Protecting application configuration
Do not hardcode database credentials inside source code or commit them to a public repository.
Use secure application configuration, environment variables, or a managed secrets service.
18. MongoDB with C# and .NET
The official MongoDB .NET/C# Driver allows .NET applications to communicate with MongoDB using C# objects and asynchronous database operations.
How .NET communicates with MongoDB
- ASP.NET Core receives an HTTP request.
- A controller or endpoint calls an application service.
- The service communicates with a MongoDB repository or collection.
- The MongoDB driver converts C# objects into BSON documents.
- MongoDB processes the operation.
- The result is mapped back into C# objects.
- The API returns an HTTP response.
MongoDB vs SQL Server integration in .NET
| SQL Server | MongoDB |
|---|---|
| Microsoft.Data.SqlClient | MongoDB.Driver |
| DbContext with EF Core | IMongoDatabase and IMongoCollection |
| DbSet | IMongoCollection |
| LINQ to Entities | MongoDB LINQ provider |
| SQL queries | MongoDB Query API |
| Entity configuration | BSON class mapping and serialization configuration |
| Migrations | Application-managed schema and data evolution strategies |
Official MongoDB .NET/C# Driver
MongoDB.Driver is the official driver package used to integrate MongoDB with C# applications.
Install the package
dotnet add package MongoDB.Driver
Creating a C# model
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
public class Employee
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string? Id { get; set; }
[BsonElement("name")]
public string Name { get; set; } = string.Empty;
[BsonElement("department")]
public string Department { get; set; } = string.Empty;
[BsonElement("salary")]
public decimal Salary { get; set; }
[BsonElement("isActive")]
public bool IsActive { get; set; }
}
Understanding BSON attributes
| Attribute | Purpose |
|---|---|
[BsonId] | Maps a property to MongoDB's _id field. |
[BsonElement] | Specifies the stored field name. |
[BsonRepresentation] | Configures how a value is represented in BSON. |
[BsonIgnore] | Excludes a property from serialization. |
[BsonIgnoreExtraElements] | Allows deserialization to ignore additional document fields. |
19. Working with MongoDB .NET/C# Driver
Connecting to MongoDB
using MongoDB.Driver;
string connectionString =
"mongodb://localhost:27017";
var client = new MongoClient(connectionString);
var database = client.GetDatabase(
"SkillsTutorials"
);
var employees = database.GetCollection(
"employees"
);
Understanding driver interfaces
| Interface or class | Purpose |
|---|---|
IMongoClient | Represents the MongoDB client. |
IMongoDatabase | Represents a database. |
IMongoCollection<T> | Represents a strongly typed collection. |
FilterDefinition<T> | Defines document selection criteria. |
UpdateDefinition<T> | Defines document update operations. |
IAsyncCursor<T> | Represents asynchronous query results. |
Insert a document
var employee = new Employee
{
Name = "Alex",
Department = "Development",
Salary = 60000,
IsActive = true
};
await employees.InsertOneAsync(employee);
Retrieve documents
var allEmployees = await employees
.Find(_ => true)
.ToListAsync();
var employee = await employees
.Find(x => x.Name == "Alex")
.FirstOrDefaultAsync();
Update a document
var filter = Builders.Filter
.Eq(x => x.Name, "Alex");
var update = Builders.Update
.Set(x => x.Salary, 65000);
var result = await employees.UpdateOneAsync(
filter,
update
);
Delete a document
var result = await employees.DeleteOneAsync(
x => x.Name == "Alex"
);
Count documents
var count = await employees.CountDocumentsAsync(
x => x.Department == "Development"
);
Pagination
int pageNumber = 1;
int pageSize = 10;
var results = await employees
.Find(_ => true)
.SortBy(x => x.Name)
.Skip((pageNumber - 1) * pageSize)
.Limit(pageSize)
.ToListAsync();
Bulk operations
Bulk writes allow multiple insert, update, replace, and delete operations to be submitted together.
var operations = new WriteModel[]
{
new InsertOneModel(
new Employee
{
Name = "Sam",
Department = "Testing",
Salary = 45000
}
),
new UpdateOneModel(
Builders.Filter
.Eq(x => x.Name, "Alex"),
Builders.Update
.Set(x => x.IsActive, true)
)
};
var bulkResult = await employees.BulkWriteAsync(
operations
);
20. MongoDB integration with ASP.NET Core Web API
A typical ASP.NET Core application should separate configuration, data access, business logic, and HTTP request handling.
Suggested project structure
MongoDbApi/
│
├── Controllers/
│ └── EmployeesController.cs
│
├── Models/
│ └── Employee.cs
│
├── Data/
│ └── MongoDbSettings.cs
│
├── Services/
│ ├── IEmployeeService.cs
│ └── EmployeeService.cs
│
├── appsettings.json
│
└── Program.cs
Step 1: Configure MongoDB settings
public class MongoDbSettings
{
public string ConnectionString { get; set; }
= string.Empty;
public string DatabaseName { get; set; }
= string.Empty;
public string EmployeeCollectionName { get; set; }
= string.Empty;
}
Step 2: Configure appsettings.json
{
"MongoDbSettings": {
"ConnectionString": "mongodb://localhost:27017",
"DatabaseName": "SkillsTutorials",
"EmployeeCollectionName": "employees"
}
}
Step 3: Register MongoDB in Program.cs
using MongoDB.Driver;
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<MongoDbSettings>(
builder.Configuration.GetSection("MongoDbSettings")
);
builder.Services.AddSingleton<IMongoClient>(sp =>
{
var settings = sp
.GetRequiredService<
Microsoft.Extensions.Options.IOptions<
MongoDbSettings
>
>().Value;
return new MongoClient(settings.ConnectionString);
});
builder.Services.AddSingleton<IMongoDatabase>(sp =>
{
var settings = sp
.GetRequiredService<
Microsoft.Extensions.Options.IOptions<
MongoDbSettings
>().Value;
var client = sp.GetRequiredService<IMongoClient>();
return client.GetDatabase(settings.DatabaseName);
});
builder.Services.AddScoped<IEmployeeService, EmployeeService>();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Why Singleton for MongoClient?
MongoClient is designed to be thread-safe and reused throughout the application. Creating a new client for every request can result in unnecessary connection pools and resource overhead.
Step 4: Create the service interface
public interface IEmployeeService
{
Task<List<Employee>> GetAllAsync();
Task<Employee?> GetByIdAsync(string id);
Task CreateAsync(Employee employee);
Task UpdateAsync(string id, Employee employee);
Task DeleteAsync(string id);
}
Step 5: Implement the service
using Microsoft.Extensions.Options;
using MongoDB.Driver;
public class EmployeeService : IEmployeeService
{
private readonly IMongoCollection<Employee> _employees;
public EmployeeService(
IMongoDatabase database,
IOptions<MongoDbSettings> options)
{
_employees = database.GetCollection<Employee>(
options.Value.EmployeeCollectionName
);
}
public async Task<List<Employee>> GetAllAsync()
{
return await _employees
.Find(_ => true)
.ToListAsync();
}
public async Task<Employee?> GetByIdAsync(string id)
{
if (!MongoDB.Bson.ObjectId.TryParse(id, out _))
return null;
return await _employees
.Find(x => x.Id == id)
.FirstOrDefaultAsync();
}
public async Task CreateAsync(Employee employee)
{
await _employees.InsertOneAsync(employee);
}
public async Task UpdateAsync(
string id,
Employee employee)
{
if (!MongoDB.Bson.ObjectId.TryParse(id, out _))
throw new ArgumentException("Invalid employee ID");
var filter = Builders<Employee>.Filter
.Eq(x => x.Id, id);
var update = Builders<Employee>.Update
.Set(x => x.Name, employee.Name)
.Set(x => x.Department, employee.Department)
.Set(x => x.Salary, employee.Salary)
.Set(x => x.IsActive, employee.IsActive);
await _employees.UpdateOneAsync(filter, update);
}
public async Task DeleteAsync(string id)
{
if (!MongoDB.Bson.ObjectId.TryParse(id, out _))
throw new ArgumentException("Invalid employee ID");
await _employees.DeleteOneAsync(
x => x.Id == id
);
}
}
Step 6: Create the controller
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class EmployeesController : ControllerBase
{
private readonly IEmployeeService _service;
public EmployeesController(IEmployeeService service)
{
_service = service;
}
[HttpGet]
public async Task<IActionResult> GetAll()
{
var employees = await _service.GetAllAsync();
return Ok(employees);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(string id)
{
var employee = await _service.GetByIdAsync(id);
if (employee == null)
return NotFound();
return Ok(employee);
}
[HttpPost]
public async Task<IActionResult> Create(Employee employee)
{
await _service.CreateAsync(employee);
return CreatedAtAction(
nameof(GetById),
new { id = employee.Id },
employee
);
}
[HttpPut("{id}")]
public async Task<IActionResult> Update(
string id,
Employee employee)
{
var existing = await _service.GetByIdAsync(id);
if (existing == null)
return NotFound();
await _service.UpdateAsync(id, employee);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(string id)
{
var existing = await _service.GetByIdAsync(id);
if (existing == null)
return NotFound();
await _service.DeleteAsync(id);
return NoContent();
}
}
This demonstrates the basic integration flow. A production implementation should also include request DTOs, input validation, centralized exception handling, logging, authorization, and appropriate pagination.
21. Repository pattern and service layer
What is the repository pattern?
The repository pattern separates data-access operations from application business logic. It provides an abstraction over the underlying data store.
Repository vs service
| Repository | Service |
|---|---|
| Responsible for data access. | Responsible for application or business logic. |
| Communicates with MongoDB collections. | Coordinates application operations. |
| Implements database queries. | Calls repositories or database abstractions. |
Example repository interface
public interface IEmployeeRepository
{
Task<List<Employee>> GetAllAsync();
Task<Employee?> GetByIdAsync(string id);
Task AddAsync(Employee employee);
Task UpdateAsync(string id, Employee employee);
Task DeleteAsync(string id);
}
A repository implementation can encapsulate MongoDB collection operations while the service layer handles business rules and orchestration.
22. LINQ and strongly typed queries
The MongoDB .NET/C# Driver supports strongly typed queries and LINQ. This allows C# developers to express database operations using familiar language constructs.
Filtering with LINQ
var employees = await collection
.AsQueryable()
.Where(x => x.Department == "Development")
.ToListAsync();
Projection
var employeeDetails = await collection
.AsQueryable()
.Where(x => x.IsActive)
.Select(x => new
{
x.Name,
x.Department
})
.ToListAsync();
Grouping
var departmentSummary = await collection
.AsQueryable()
.GroupBy(x => x.Department)
.Select(group => new
{
Department = group.Key,
Count = group.Count()
})
.ToListAsync();
Builder syntax
The driver also provides filter, update, projection, and sort builders.
var filter = Builders<Employee>.Filter
.Gt(x => x.Salary, 50000);
var sort = Builders<Employee>.Sort
.Descending(x => x.Salary);
var results = await collection
.Find(filter)
.Sort(sort)
.ToListAsync();
23. BSON serialization and mapping
Serialization converts C# objects into BSON documents for storage. Deserialization converts BSON documents back into C# objects.
Automatic mapping
public class Product
{
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
Custom field names
public class Product
{
[BsonElement("product_name")]
public string Name { get; set; } = "";
[BsonElement("unit_price")]
public decimal Price { get; set; }
}
Convention-based mapping
Convention packs allow consistent mapping rules to be applied across multiple classes.
var conventionPack = new ConventionPack
{
new CamelCaseElementNameConvention()
};
ConventionRegistry.Register(
"CamelCaseConvention",
conventionPack,
type => true
);
Register global conventions during application startup, before the affected classes are mapped or serialized.
Handling extra fields
[BsonIgnoreExtraElements]
public class Product
{
[BsonId]
public ObjectId Id { get; set; }
public string Name { get; set; } = "";
}
Custom serializers
Custom serializers are useful when the default BSON mapping does not match an application's domain model or storage requirements.
The driver provides the IBsonSerializer interface and a serializer registry for custom serialization behaviour.
24. Performance and best practices
Database design
- Design documents around actual application access patterns.
- Embed related data when it is commonly read together.
- Use references when independent access or unbounded relationships require them.
- Avoid excessively large documents and unbounded arrays.
- Choose field types carefully.
Query performance
- Create indexes for frequently used query patterns.
- Use projection to retrieve only required fields.
- Use pagination for large result sets.
- Review execution plans using explain.
- Monitor index usage and remove unnecessary indexes.
- Prefer efficient query filters.
.NET application practices
- Reuse MongoClient as a long-lived application service.
- Use asynchronous database operations.
- Use strongly typed collections where appropriate.
- Keep connection strings outside source code.
- Use dependency injection.
- Validate incoming API data.
- Implement centralized error handling.
- Use cancellation tokens for cancellable operations.
- Monitor database operation duration and failures.
Asynchronous operations with cancellation
public async Task<List<Employee>> GetEmployeesAsync(
CancellationToken cancellationToken)
{
return await _employees
.Find(_ => true)
.ToListAsync(cancellationToken);
}
25. Advanced MongoDB capabilities
MongoDB Atlas Search
Atlas Search provides full-text search capabilities using an index-based search engine integrated with MongoDB Atlas.
It supports features such as text search, filtering, autocomplete, and relevance scoring.
Vector Search
MongoDB Vector Search supports similarity search over vector embeddings. It can be used in AI applications, semantic retrieval, and retrieval-augmented generation workflows.
Common use cases include:
- Semantic document search.
- Recommendation systems.
- Knowledge retrieval.
- AI-powered search applications.
Time-series collections
Time-series collections are optimized for storing and querying time-stamped measurements.
Examples include application telemetry, IoT measurements, monitoring metrics, and sensor events.
Change Streams
Change Streams allow applications to observe database changes in real time without continuously polling collections.
They can be useful for notification systems, event-driven workflows, and synchronization scenarios.
GridFS
GridFS provides a mechanism for storing and retrieving files that exceed the normal BSON document size limit. It stores file content in chunks across dedicated collections.
Time series vs regular collections
| Regular collection | Time-series collection |
|---|---|
| General-purpose document storage. | Optimized for time-stamped measurements. |
| General document access patterns. | Time-oriented query patterns. |
| Flexible application records. | Monitoring, sensor and event measurements. |
26. Backup, monitoring and deployment
Backup and restore
Database backups protect against accidental deletion, corruption, operational failures, and other data-loss scenarios.
MongoDB provides backup and restore tools and managed backup capabilities depending on the deployment and service tier.
Monitoring
Important monitoring areas include:
- Database availability.
- Query execution time.
- Slow queries.
- CPU and memory usage.
- Storage utilization.
- Connection usage.
- Replication health and lag.
- Index usage.
Deployment options
| Deployment | Description |
|---|---|
| Local server | Development and testing. |
| Self-managed server | Organization-managed infrastructure. |
| MongoDB Atlas | Managed cloud database deployment. |
Production checklist
- Use an appropriate supported MongoDB version.
- Configure authentication and authorization.
- Restrict network access.
- Use TLS for database connections.
- Secure application secrets.
- Create indexes based on workload requirements.
- Implement reliable backup and restore procedures.
- Monitor database health and query performance.
- Test failover and recovery procedures.
- Use appropriate replication and sharding architecture where needed.
27. Suggested learning and practice roadmap
Follow this progression to move from basic MongoDB operations to developing production-oriented .NET applications.
| Stage | Focus | Practice outcome |
|---|---|---|
| Beginner | NoSQL, databases, collections, documents, BSON and CRUD. | Understand document databases and perform basic operations. |
| Intermediate | Queries, operators, document modelling, references, validation and indexes. | Design efficient document structures and queries. |
| Advanced | Aggregation, transactions, replication, sharding and security. | Understand database performance, consistency and scalability. |
| .NET Integration | C# Driver, BSON mapping, LINQ, asynchronous operations and dependency injection. | Connect MongoDB with C# applications. |
| Full-stack development | ASP.NET Core Web API, repository pattern, services, CRUD and authentication. | Build complete backend applications. |
| Production-ready | Monitoring, backups, deployment, security and optimization. | Operate and maintain reliable MongoDB applications. |
Recommended practical projects
- Employee Management API: Implement employee CRUD operations using MongoDB and ASP.NET Core.
- Product Catalogue: Practise embedded documents, filtering, sorting, and indexes.
- Order Management System: Work with customers, orders, product references and aggregation.
- Task Management Application: Practise document modelling, status updates and pagination.
- Analytics Dashboard: Use aggregation pipelines for reporting.
- Real-Time Monitoring Application: Explore time-series collections and Change Streams.
- AI Knowledge Search: Explore embeddings and MongoDB Vector Search.
Final thoughts
MongoDB is more than a database that stores JSON-like documents. It provides a complete data platform with querying, indexing, aggregation, transactions, replication, and distributed scaling capabilities.
For .NET developers, understanding the official C# Driver is especially important. Learn how C# objects map to BSON documents, how to execute asynchronous CRUD operations, how to build strongly typed queries, and how to integrate database access into ASP.NET Core using dependency injection and clean application architecture.
Start with the fundamentals, practise MongoDB Shell operations, and then build a complete ASP.NET Core Web API backed by MongoDB. This combination will give you a practical understanding of both document database concepts and real-world .NET application development.