LEARN BUILD GROW TOGETHER
DEVELOPER LEARNING HUB
Learn. Build. Grow Together.

Practical tutorials, real-world examples and interview preparation.

.NETC#SQL SERVERANGULAR
Home /ASP.NET Core /MongoDB: Complete Developer Learning Guide

MongoDB: Complete Developer Learning Guide

November 14, 2026 5 min read , , , , , ,

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.

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 typeData modelExamples
DocumentJSON-like documentsMongoDB
Key-valueKey and associated valueRedis
Wide-columnColumn familiesApache Cassandra
GraphNodes and relationshipsNeo4j

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 ServerMongoDB
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 ServerMongoDB
DatabaseDatabase
TableCollection
RowDocument
ColumnField
Primary key_id
IndexIndex
Stored procedureNo 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.
MongoDB is not automatically better than SQL Server. Database selection should be based on application requirements, data relationships, consistency needs, query patterns, and operational considerations.

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

DeploymentDescription
Community ServerSelf-managed MongoDB deployment.
Enterprise ServerCommercial self-managed deployment with enterprise features.
MongoDB AtlasManaged 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

JSONBSON
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

TypeDescription
StringTextual values.
Int3232-bit integer.
Int6464-bit integer.
DoubleFloating-point number.
Decimal128128-bit decimal value.
BooleanTrue or false.
DateDate/time represented as milliseconds since Unix epoch.
ObjectId12-byte BSON identifier.
ArrayOrdered collection of values.
ObjectEmbedded document.
NullNull 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 Shell Download

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.

MongoDB Atlas

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/
Never publish a real MongoDB connection string containing credentials. Store secrets securely and configure appropriate database users and network access rules.

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.

MongoDB Compass

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"
})
Always verify your filter before executing update or delete operations. An empty filter can match every document in the collection.

8. Query operators and projections

Comparison operators

OperatorPurpose
$eqEqual to.
$neNot equal to.
$gtGreater than.
$gteGreater than or equal to.
$ltLess than.
$lteLess than or equal to.
$inMatches any value in an array.
$ninDoes 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"
        }
    }
])
MongoDB supports joins through aggregation, but document modelling should begin with application query patterns rather than attempting to reproduce every relational schema directly.

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.
Application-level validation and database-level schema validation serve different purposes. Use both when the application requires clear user-facing validation and consistent stored data.

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.
Indexes improve suitable read operations but require additional storage and maintenance during writes. More indexes do not automatically mean better performance.

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

StagePurpose
$matchFilters documents.
$projectSelects or transforms fields.
$groupGroups documents and calculates values.
$sortSorts documents.
$limitLimits results.
$skipSkips documents.
$unwindDeconstructs array fields.
$lookupJoins related collections.
$countCounts pipeline documents.
$setAdds 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.
Prefer appropriate document modelling and single-document atomic updates where possible. Multi-document transactions have additional operational costs and should be used when business consistency requires them.

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

  1. The primary receives a write operation.
  2. The operation is recorded in the replication log (oplog).
  3. Secondaries replicate the changes.
  4. Replica set members participate in elections when the primary becomes unavailable.
  5. An eligible secondary can become the new primary.
Replication provides redundancy and availability, but it is not a substitute for backups. Replication also does not automatically guarantee that every read from a secondary returns the newest data.

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

ComponentResponsibility
ShardStores a portion of the sharded data.
Config serversStore cluster metadata and configuration.
MongosRoutes client requests to the appropriate shards.
Shard keyDetermines 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.
Poor shard key selection can cause uneven data distribution, hotspots, and inefficient queries. Sharding should be introduced based on measured requirements, not simply because an application uses MongoDB.

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 ServerMongoDB
Microsoft.Data.SqlClientMongoDB.Driver
DbContext with EF CoreIMongoDatabase and IMongoCollection
DbSetIMongoCollection
LINQ to EntitiesMongoDB LINQ provider
SQL queriesMongoDB Query API
Entity configurationBSON class mapping and serialization configuration
MigrationsApplication-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.

MongoDB.Driver on NuGet

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

AttributePurpose
[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 classPurpose
IMongoClientRepresents the MongoDB client.
IMongoDatabaseRepresents 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"
  }
}
This local development example uses a connection string without credentials. For production, use a secure configuration provider or secrets manager instead of committing database credentials to appsettings.json.

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

RepositoryService
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.

The repository pattern is an architectural choice, not a MongoDB requirement. Avoid creating excessive abstraction when a straightforward service using IMongoCollection is sufficient.

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();
The MongoDB .NET/C# Driver uses LINQ3 as its LINQ provider. Not every LINQ expression is supported for translation, so inspect generated queries and test the operations used by your application.

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 collectionTime-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

DeploymentDescription
Local serverDevelopment and testing.
Self-managed serverOrganization-managed infrastructure.
MongoDB AtlasManaged 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.

StageFocusPractice outcome
BeginnerNoSQL, databases, collections, documents, BSON and CRUD.Understand document databases and perform basic operations.
IntermediateQueries, operators, document modelling, references, validation and indexes.Design efficient document structures and queries.
AdvancedAggregation, transactions, replication, sharding and security.Understand database performance, consistency and scalability.
.NET IntegrationC# Driver, BSON mapping, LINQ, asynchronous operations and dependency injection.Connect MongoDB with C# applications.
Full-stack developmentASP.NET Core Web API, repository pattern, services, CRUD and authentication.Build complete backend applications.
Production-readyMonitoring, backups, deployment, security and optimization.Operate and maintain reliable MongoDB applications.

Recommended practical projects

  1. Employee Management API: Implement employee CRUD operations using MongoDB and ASP.NET Core.
  2. Product Catalogue: Practise embedded documents, filtering, sorting, and indexes.
  3. Order Management System: Work with customers, orders, product references and aggregation.
  4. Task Management Application: Practise document modelling, status updates and pagination.
  5. Analytics Dashboard: Use aggregation pipelines for reporting.
  6. Real-Time Monitoring Application: Explore time-series collections and Change Streams.
  7. 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.

Skills Tutorials · Learn • Build • Grow Together