MongoDB.Abstracts
6.6.0
dotnet add package MongoDB.Abstracts --version 6.6.0
NuGet\Install-Package MongoDB.Abstracts -Version 6.6.0
<PackageReference Include="MongoDB.Abstracts" Version="6.6.0" />
<PackageVersion Include="MongoDB.Abstracts" Version="6.6.0" />
<PackageReference Include="MongoDB.Abstracts" />
paket add MongoDB.Abstracts --version 6.6.0
#r "nuget: MongoDB.Abstracts, 6.6.0"
#:package MongoDB.Abstracts@6.6.0
#addin nuget:?package=MongoDB.Abstracts&version=6.6.0
#tool nuget:?package=MongoDB.Abstracts&version=6.6.0
MongoDB.Abstracts
A modern .NET library that provides abstract base classes and interfaces for implementing the repository pattern with MongoDB. Simplify your MongoDB data access layer with strongly-typed repositories, automatic auditing, and dependency injection support.
Features
- Generic Repository Pattern: Type-safe repository interfaces and base classes for MongoDB
- Automatic Auditing: Built-in support for tracking entity creation and modification timestamps
- Dependency Injection: Seamless integration with .NET's dependency injection container
- Multi-Database Support: Connection discrimination for working with multiple MongoDB databases
- LINQ Support: Full IQueryable support for complex queries
- Async/Await: Complete async operation support for modern applications
- Custom Repository Extensions: Easy override points for specialized repository behavior
Installation
Package Manager Console
Install-Package MongoDB.Abstracts
.NET CLI
dotnet add package MongoDB.Abstracts
PackageReference
<PackageReference Include="MongoDB.Abstracts" />
More information available at nuget.org/packages/MongoDB.Abstracts
Core Interfaces and Classes
Entity Interfaces
IMongoEntity
- Base interface for MongoDB entities with Id, Created, and Updated propertiesMongoEntity
- Base class implementing IMongoEntity with common MongoDB entity behavior
Repository Interfaces
IMongoQuery<TEntity, TKey>
- Interface for generic MongoDB query operationsIMongoRepository<TEntity, TKey>
- Interface for generic MongoDB repository operationsIMongoEntityRepository<TEntity>
- Specialized repository interface for IMongoEntity typesIMongoEntityRepository<TDiscriminator, TEntity>
- Multi-database discriminator support
Repository Implementations
MongoQuery<TEntity, TKey>
- Base class for MongoDB query operationsMongoRepository<TEntity, TKey>
- Base class for MongoDB repository operationsMongoEntityRepository<TEntity>
- Entity-specific repository implementation
Configuration
Basic Setup
Register MongoDB repositories with dependency injection using a connection string:
// Direct connection string
services.AddMongoRepository("mongodb://localhost:27017/MyDatabase");
// Connection string from configuration
services.AddMongoRepository("MyDatabase");
appsettings.json:
{
"ConnectionStrings": {
"MyDatabase": "mongodb://localhost:27017/MyDatabase"
}
}
Multi-Database Configuration with Discriminators
For applications requiring multiple MongoDB connections, use discriminator types to distinguish between different database contexts:
1. Define Discriminator Types
public readonly struct ProductsConnection;
public readonly struct InventoryConnection;
public readonly struct UsersConnection;
2. Register Multiple Connections
services.AddMongoRepository<ProductsConnection>("ProductsConnection");
services.AddMongoRepository<InventoryConnection>("InventoryConnection");
services.AddMongoRepository<UsersConnection>("UsersConnection");
3. Configuration
appsettings.json:
{
"ConnectionStrings": {
"ProductsConnection": "mongodb://localhost:27017/Products",
"InventoryConnection": "mongodb://localhost:27017/Inventory",
"UsersConnection": "mongodb://localhost:27017/Users"
}
}
4. Dependency Injection
public class ProductService
{
private readonly IMongoEntityRepository<ProductsConnection, Product> _repository;
public ProductService(IMongoEntityRepository<ProductsConnection, Product> repository)
{
_repository = repository;
}
public async Task<Product> GetProductAsync(string id)
{
return await _repository.FindAsync(id);
}
}
public class InventoryService
{
private readonly IMongoEntityRepository<InventoryConnection, Inventory> _repository;
public InventoryService(IMongoEntityRepository<InventoryConnection, Inventory> repository)
{
_repository = repository;
}
public async Task<List<Inventory>> GetLowStockItemsAsync()
{
return await _repository.FindAllAsync(i => i.Quantity < 10);
}
}
Usage Examples
Define Your Entity
public class Product : MongoEntity
{
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public decimal Price { get; set; }
public int Stock { get; set; }
public string Category { get; set; } = string.Empty;
public bool IsActive { get; set; } = true;
}
Basic CRUD Operations
Create (Insert)
var productRepo = serviceProvider.GetRequiredService<IMongoEntityRepository<Product>>();
var product = new Product
{
Name = "Gaming Laptop",
Description = "High-performance gaming laptop",
Price = 1299.99m,
Stock = 5,
Category = "Electronics"
};
var createdProduct = await productRepo.InsertAsync(product);
Console.WriteLine($"Created product with ID: {createdProduct.Id}");
Read (Find)
// Find by ID
var product = await productRepo.FindAsync("67a0dc52fa5ebe49f293a374");
// Find single entity with query
var expensiveProduct = await productRepo.FindOneAsync(p => p.Price > 1000);
// Find multiple entities
var electronicsProducts = await productRepo.FindAllAsync(p => p.Category == "Electronics");
// Find with LINQ
var activeProducts = productRepo.All()
.Where(p => p.IsActive && p.Stock > 0)
.OrderBy(p => p.Name)
.ToListAsync();
Update
// Find and update
var product = await productRepo.FindAsync("67a0dc52fa5ebe49f293a374");
if (product != null)
{
product.Price = 1199.99m;
product.Stock = 3;
var updatedProduct = await productRepo.UpdateAsync(product);
Console.WriteLine($"Updated product: {updatedProduct.Name}");
}
Delete
// Delete by ID
var deletedCount = await productRepo.DeleteAsync("67a0dc52fa5ebe49f293a374");
Console.WriteLine($"Deleted {deletedCount} product(s)");
// Delete with query
var deletedInactiveCount = await productRepo.DeleteAllAsync(p => !p.IsActive);
Console.WriteLine($"Deleted {deletedInactiveCount} inactive product(s)");
Advanced Querying
Complex LINQ Queries
var productRepo = serviceProvider.GetRequiredService<IMongoEntityRepository<Product>>();
// Complex filtering with pagination
var expensiveElectronics = await productRepo.All()
.Where(p => p.Category == "Electronics" && p.Price > 500)
.Where(p => p.IsActive && p.Stock > 0)
.OrderByDescending(p => p.Price)
.ThenBy(p => p.Name)
.Skip(0)
.Take(10)
.ToListAsync();
// Aggregation-style queries
var categoryStats = productRepo.All()
.Where(p => p.IsActive)
.GroupBy(p => p.Category)
.Select(g => new
{
Category = g.Key,
Count = g.Count(),
AveragePrice = g.Average(p => p.Price),
TotalValue = g.Sum(p => p.Price * p.Stock)
})
.ToList();
Using MongoDB Filters
using MongoDB.Driver;
// Using MongoDB.Driver filters for advanced scenarios
var filter = Builders<Product>.Filter.And(
Builders<Product>.Filter.Eq(p => p.Category, "Electronics"),
Builders<Product>.Filter.Gte(p => p.Price, 100),
Builders<Product>.Filter.Lte(p => p.Price, 1000)
);
var products = await productRepo.FindAllAsync(filter);
Custom Repository Implementation
Create specialized repositories by inheriting from the base classes:
public class ProductRepository : MongoEntityRepository<Product>
{
public ProductRepository(IMongoDatabase mongoDatabase) : base(mongoDatabase)
{
}
// Custom business logic before insert
protected override void BeforeInsert(Product entity)
{
base.BeforeInsert(entity);
// Auto-generate SKU
entity.SKU = GenerateSKU(entity.Category, entity.Name);
// Validate business rules
ValidateProductRules(entity);
}
// Custom business logic before update
protected override void BeforeUpdate(Product entity)
{
base.BeforeUpdate(entity);
// Re-validate business rules
ValidateProductRules(entity);
// Update search tags
entity.SearchTags = GenerateSearchTags(entity);
}
// Ensure custom indexes
protected override void EnsureIndexes(IMongoCollection<Product> mongoCollection)
{
base.EnsureIndexes(mongoCollection);
// Create compound index for category and price
mongoCollection.Indexes.CreateOne(
new CreateIndexModel<Product>(
Builders<Product>.IndexKeys
.Ascending(p => p.Category)
.Descending(p => p.Price),
new CreateIndexOptions { Name = "category_price_idx" }
)
);
// Create text index for search
mongoCollection.Indexes.CreateOne(
new CreateIndexModel<Product>(
Builders<Product>.IndexKeys.Text(p => p.Name).Text(p => p.Description),
new CreateIndexOptions { Name = "text_search_idx" }
)
);
// Create unique index on SKU
mongoCollection.Indexes.CreateOne(
new CreateIndexModel<Product>(
Builders<Product>.IndexKeys.Ascending(p => p.SKU),
new CreateIndexOptions { Unique = true, Name = "sku_unique_idx" }
)
);
}
// Custom repository methods
public async Task<List<Product>> FindByPriceRangeAsync(decimal minPrice, decimal maxPrice)
{
return await FindAllAsync(p => p.Price >= minPrice && p.Price <= maxPrice && p.IsActive);
}
public async Task<Product?> FindBySKUAsync(string sku)
{
return await FindOneAsync(p => p.SKU == sku);
}
public async Task<bool> IsStockAvailableAsync(string productId, int requestedQuantity)
{
var product = await FindAsync(productId);
return product?.Stock >= requestedQuantity;
}
private string GenerateSKU(string category, string name)
{
// Implementation for SKU generation
var categoryCode = category.ToUpperInvariant().Substring(0, Math.Min(3, category.Length));
var nameCode = string.Concat(name.Where(char.IsLetterOrDigit)).ToUpperInvariant();
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
return $"{categoryCode}-{nameCode}-{timestamp}";
}
private void ValidateProductRules(Product entity)
{
if (entity.Price <= 0)
throw new ArgumentException("Product price must be greater than zero");
if (string.IsNullOrWhiteSpace(entity.Name))
throw new ArgumentException("Product name is required");
if (entity.Stock < 0)
throw new ArgumentException("Product stock cannot be negative");
}
private List<string> GenerateSearchTags(Product entity)
{
var tags = new List<string>();
// Add category tags
tags.Add(entity.Category.ToLowerInvariant());
// Add name words
tags.AddRange(entity.Name.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(w => w.ToLowerInvariant()));
// Add price range tags
if (entity.Price < 50) tags.Add("budget");
else if (entity.Price > 1000) tags.Add("premium");
else tags.Add("mid-range");
return tags.Distinct().ToList();
}
}
Entity Auditing
The IMongoEntity
interface automatically provides auditing capabilities:
public class AuditableProduct : MongoEntity
{
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
// Additional audit fields (beyond base Created/Updated)
public string CreatedBy { get; set; } = string.Empty;
public string UpdatedBy { get; set; } = string.Empty;
}
public class AuditableProductRepository : MongoEntityRepository<AuditableProduct>
{
private readonly ICurrentUserService _currentUserService;
public AuditableProductRepository(
IMongoDatabase mongoDatabase,
ICurrentUserService currentUserService)
: base(mongoDatabase)
{
_currentUserService = currentUserService;
}
protected override void BeforeInsert(AuditableProduct entity)
{
base.BeforeInsert(entity); // Sets Created and Updated timestamps
entity.CreatedBy = _currentUserService.GetCurrentUserId();
}
protected override void BeforeUpdate(AuditableProduct entity)
{
base.BeforeUpdate(entity); // Updates the Updated timestamp
entity.UpdatedBy = _currentUserService.GetCurrentUserId();
}
}
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.8)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.8)
- MongoDB.Driver (>= 3.4.3)
-
net8.0
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.8)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.8)
- MongoDB.Driver (>= 3.4.3)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on MongoDB.Abstracts:
Package | Downloads |
---|---|
MediatR.CommandQuery.MongoDB
CQRS framework based on MediatR |
|
Arbiter.CommandQuery.MongoDB
Command Query Responsibility Segregation (CQRS) framework based on mediator pattern using Mongo DB as the data store handler |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
6.6.0 | 32 | 9/3/2025 |
6.5.0 | 477 | 5/25/2025 |
6.4.0 | 322 | 4/18/2025 |
6.3.0 | 434 | 2/4/2025 |
6.2.0 | 132 | 2/4/2025 |
6.1.0 | 138 | 2/3/2025 |
6.0.0 | 131 | 2/3/2025 |
5.7.1 | 723 | 7/26/2024 |
5.7.0 | 492 | 5/10/2024 |
5.6.1 | 754 | 7/28/2023 |
5.5.269 | 1,075 | 12/28/2022 |
5.5.219 | 994 | 4/23/2022 |
5.5.216 | 727 | 3/21/2022 |
5.5.191 | 841 | 12/22/2021 |
5.5.172 | 1,235 | 10/29/2021 |
5.0.0.166 | 441 | 10/21/2021 |
5.0.0.128 | 440 | 6/5/2021 |
4.0.0.102 | 524 | 2/15/2021 |
4.0.0.83 | 588 | 10/26/2020 |
4.0.0.80 | 602 | 10/17/2020 |
3.0.0.79 | 621 | 10/17/2020 |
3.0.0.56 | 754 | 5/9/2020 |
3.0.0.36 | 873 | 3/16/2020 |
2.0.0.10 | 884 | 4/23/2019 |
2.0.0.8 | 1,232 | 4/27/2017 |
2.0.0.7 | 1,197 | 4/4/2017 |
1.0.0.5 | 1,298 | 5/4/2016 |
1.0.0.3 | 1,250 | 4/30/2016 |
1.0.0.2 | 1,467 | 4/21/2016 |