MongoDB.Abstracts 6.6.0

dotnet add package MongoDB.Abstracts --version 6.6.0
                    
NuGet\Install-Package MongoDB.Abstracts -Version 6.6.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MongoDB.Abstracts" Version="6.6.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MongoDB.Abstracts" Version="6.6.0" />
                    
Directory.Packages.props
<PackageReference Include="MongoDB.Abstracts" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MongoDB.Abstracts --version 6.6.0
                    
#r "nuget: MongoDB.Abstracts, 6.6.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MongoDB.Abstracts@6.6.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MongoDB.Abstracts&version=6.6.0
                    
Install as a Cake Addin
#tool nuget:?package=MongoDB.Abstracts&version=6.6.0
                    
Install as a Cake Tool

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.

Build status NuGet Version Coverage Status

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 properties
  • MongoEntity - Base class implementing IMongoEntity with common MongoDB entity behavior

Repository Interfaces

  • IMongoQuery<TEntity, TKey> - Interface for generic MongoDB query operations
  • IMongoRepository<TEntity, TKey> - Interface for generic MongoDB repository operations
  • IMongoEntityRepository<TEntity> - Specialized repository interface for IMongoEntity types
  • IMongoEntityRepository<TDiscriminator, TEntity> - Multi-database discriminator support

Repository Implementations

  • MongoQuery<TEntity, TKey> - Base class for MongoDB query operations
  • MongoRepository<TEntity, TKey> - Base class for MongoDB repository operations
  • MongoEntityRepository<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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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