Indiko.Blocks.DataAccess.MongoDb
2.1.1
dotnet add package Indiko.Blocks.DataAccess.MongoDb --version 2.1.1
NuGet\Install-Package Indiko.Blocks.DataAccess.MongoDb -Version 2.1.1
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="Indiko.Blocks.DataAccess.MongoDb" Version="2.1.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Indiko.Blocks.DataAccess.MongoDb" Version="2.1.1" />
<PackageReference Include="Indiko.Blocks.DataAccess.MongoDb" />
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 Indiko.Blocks.DataAccess.MongoDb --version 2.1.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Indiko.Blocks.DataAccess.MongoDb, 2.1.1"
#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 Indiko.Blocks.DataAccess.MongoDb@2.1.1
#: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=Indiko.Blocks.DataAccess.MongoDb&version=2.1.1
#tool nuget:?package=Indiko.Blocks.DataAccess.MongoDb&version=2.1.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Indiko.Blocks.DataAccess.MongoDb
MongoDB implementation of the Indiko data access abstractions, providing NoSQL document database support with full repository pattern.
Overview
This package provides a complete MongoDB implementation of the Indiko data access layer, supporting document-based data storage, indexing, aggregations, and transactions.
Features
- MongoDB Driver: Full MongoDB.Driver integration
- Repository Implementation: Complete IRepository<TEntity, TIdType> implementation
- Document Storage: Native document/BSON support
- Indexing: Attribute-based and fluent index configuration
- Aggregation Pipeline: Support for MongoDB aggregation framework
- Transactions: Multi-document ACID transactions
- Change Streams: Real-time change notification support
- GridFS: Large file storage support
- Flexible Schema: Schema-less document storage
- High Performance: Optimized for MongoDB operations
Installation
dotnet add package Indiko.Blocks.DataAccess.MongoDb
Quick Start
Define Your DbContext
using Indiko.Blocks.DataAccess.MongoDb;
public class AppDbContext : BaseDbContext
{
public AppDbContext(IMongoDatabase database) : base(database)
{
}
public IMongoCollection<User> Users => GetCollection<User>();
public IMongoCollection<Order> Orders => GetCollection<Order>();
protected override void OnModelCreating(MongoModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Configure collections
modelBuilder.Entity<User>(entity =>
{
entity.ToCollection("users");
entity.HasIndex(u => u.Email, unique: true);
});
modelBuilder.Entity<Order>(entity =>
{
entity.ToCollection("orders");
entity.HasIndex(o => o.OrderNumber, unique: true);
entity.HasIndex(o => o.UserId);
});
}
}
Configure Services
public class Startup : WebStartup
{
public override void ConfigureServices(IServiceCollection services)
{
base.ConfigureServices(services);
services.UseMongoDbDataAccess<AppDbContext>(options =>
{
options.ConnectionString = Configuration.GetConnectionString("MongoDB");
options.DatabaseName = "MyAppDb";
});
}
}
Entity Definition
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
public class User : BaseEntity<ObjectId>
{
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("email")]
public string Email { get; set; }
[BsonElement("age")]
public int Age { get; set; }
[BsonElement("tags")]
public List<string> Tags { get; set; }
[BsonElement("metadata")]
public Dictionary<string, object> Metadata { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
public DateTime BirthDate { get; set; }
}
Usage Examples
Basic CRUD
public class UserService
{
private readonly IRepository<User, ObjectId> _userRepository;
private readonly IUnitOfWork _unitOfWork;
public UserService(IRepository<User, ObjectId> userRepository, IUnitOfWork unitOfWork)
{
_userRepository = userRepository;
_unitOfWork = unitOfWork;
}
public async Task<User> CreateAsync(User user)
{
user.Id = ObjectId.GenerateNewId();
await _userRepository.AddAsync(user);
await _unitOfWork.SaveChangesAsync();
return user;
}
public async Task<User> GetByIdAsync(ObjectId id)
{
return await _userRepository.ReadByIdAsync(id);
}
public async Task<IEnumerable<User>> SearchByNameAsync(string name)
{
return await _userRepository.ReadManyByQueryAsync(u =>
u.Name.Contains(name, StringComparison.OrdinalIgnoreCase));
}
}
MongoDB-Specific Queries
// Array contains
var usersWithTag = await _userRepository.ReadManyByQueryAsync(u =>
u.Tags.Contains("premium"));
// Nested property queries
var activeAdults = await _userRepository.ReadManyByQueryAsync(u =>
u.Age >= 18 && u.Status == Status.Active);
// Regular expressions
var emailPattern = new BsonRegularExpression("@gmail\\.com$", "i");
var gmailUsers = await _userRepository.AsQueryable()
.Where(u => u.Email.Matches(emailPattern))
.ToListAsync();
// GeoSpatial queries (if using geo indexes)
var nearbyUsers = await _userRepository.AsQueryable()
.Where(u => u.Location.Near(longitude, latitude, maxDistance))
.ToListAsync();
Indexing
Attribute-Based Indexing
using Indiko.Blocks.DataAccess.MongoDb.Attributes;
public class Product : BaseEntity<ObjectId>
{
[MongoIndex(Unique = true)]
public string SKU { get; set; }
[MongoIndex]
public string Category { get; set; }
[MongoIndex(Name = "price_index", Order = -1)]
public decimal Price { get; set; }
// Compound index
[MongoIndex(Name = "category_price", Order = 1, CompoundWith = nameof(Price))]
public string CategoryForCompound { get; set; }
}
Fluent Index Configuration
protected override void OnModelCreating(MongoModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>(entity =>
{
entity.ToCollection("products");
// Simple index
entity.HasIndex(p => p.SKU, unique: true);
// Compound index
entity.HasIndex(
p => new { p.Category, p.Price },
name: "category_price_idx"
);
// Text index for full-text search
entity.HasTextIndex(p => p.Description);
// TTL index (auto-delete after expiration)
entity.HasTTLIndex(p => p.ExpiresAt, expireAfterSeconds: 0);
});
}
Aggregation Pipeline
// Using AsQueryable for aggregation
var topCategories = await _productRepository.AsQueryable()
.GroupBy(p => p.Category)
.Select(g => new
{
Category = g.Key,
Count = g.Count(),
TotalRevenue = g.Sum(p => p.Price),
AvgPrice = g.Average(p => p.Price)
})
.OrderByDescending(x => x.Count)
.Take(10)
.ToListAsync();
// Native aggregation pipeline
var collection = _context.GetCollection<Order>();
var pipeline = new[]
{
new BsonDocument("$match", new BsonDocument("status", "completed")),
new BsonDocument("$group", new BsonDocument
{
{ "_id", "$userId" },
{ "totalOrders", new BsonDocument("$sum", 1) },
{ "totalAmount", new BsonDocument("$sum", "$amount") }
}),
new BsonDocument("$sort", new BsonDocument("totalAmount", -1)),
new BsonDocument("$limit", 10)
};
var results = await collection.AggregateAsync<BsonDocument>(pipeline);
Transactions
public async Task TransferInventoryAsync(ObjectId fromWarehouseId, ObjectId toWarehouseId, string productId, int quantity)
{
await _unitOfWork.BeginTransactionAsync();
try
{
var warehouseRepo = _manager.GetRepository<Warehouse, ObjectId>();
var fromWarehouse = await warehouseRepo.ReadByIdAsync(fromWarehouseId);
var toWarehouse = await warehouseRepo.ReadByIdAsync(toWarehouseId);
fromWarehouse.Inventory[productId] -= quantity;
toWarehouse.Inventory[productId] += quantity;
await warehouseRepo.UpdateAsync(fromWarehouse);
await warehouseRepo.UpdateAsync(toWarehouse);
await _unitOfWork.SaveChangesAsync();
await _unitOfWork.CommitTransactionAsync();
}
catch
{
await _unitOfWork.RollbackTransactionAsync();
throw;
}
}
Change Streams
public async Task WatchForChangesAsync(CancellationToken cancellationToken)
{
var collection = _context.GetCollection<User>();
var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<User>>()
.Match(change => change.OperationType == ChangeStreamOperationType.Insert ||
change.OperationType == ChangeStreamOperationType.Update);
using var cursor = await collection.WatchAsync(pipeline, cancellationToken: cancellationToken);
await cursor.ForEachAsync(change =>
{
Console.WriteLine($"Change detected: {change.OperationType}");
Console.WriteLine($"Document: {change.FullDocument.Name}");
}, cancellationToken);
}
Configuration
appsettings.json
{
"ConnectionStrings": {
"MongoDB": "mongodb://localhost:27017"
},
"MongoDb": {
"DatabaseName": "MyAppDb",
"MaxConnectionPoolSize": 500,
"MinConnectionPoolSize": 10,
"ConnectTimeout": "30s",
"SocketTimeout": "30s",
"ServerSelectionTimeout": "30s",
"RetryWrites": true,
"RetryReads": true
}
}
Code Configuration
services.UseMongoDbDataAccess<AppDbContext>(options =>
{
options.ConnectionString = "mongodb://localhost:27017";
options.DatabaseName = "MyAppDb";
options.MaxConnectionPoolSize = 500;
options.EnableQueryLogging = env.IsDevelopment();
});
Best Practices
Use ObjectId for Primary Keys
public class MyEntity : BaseEntity<ObjectId>
{
// ObjectId is optimized for MongoDB
}
Embed Related Data for Read Performance
public class Order : BaseEntity<ObjectId>
{
public ObjectId UserId { get; set; }
// Embedded document for better read performance
public UserInfo UserInfo { get; set; }
public List<OrderItem> Items { get; set; }
}
public class UserInfo
{
public string Name { get; set; }
public string Email { get; set; }
}
Use Projections
// Only retrieve needed fields
var userNames = await _userRepository.ReadByQueryWithSelectorAsync(
where: u => u.IsActive,
selector: u => new { u.Id, u.Name }
);
Create Appropriate Indexes
// Index frequently queried fields
entity.HasIndex(u => u.Email, unique: true);
entity.HasIndex(u => u.CreatedAt);
entity.HasIndex(u => new { u.Category, u.Status });
MongoDB-Specific Features
Document Validation
var validator = new BsonDocument("$jsonSchema", new BsonDocument
{
{ "bsonType", "object" },
{ "required", new BsonArray { "name", "email" } },
{ "properties", new BsonDocument
{
{ "name", new BsonDocument("bsonType", "string") },
{ "email", new BsonDocument
{
{ "bsonType", "string" },
{ "pattern", "^.+@.+$" }
}
}
}
}
});
GridFS for Large Files
public class FileService
{
private readonly IGridFSBucket _gridFS;
public async Task<ObjectId> UploadFileAsync(Stream fileStream, string filename)
{
return await _gridFS.UploadFromStreamAsync(filename, fileStream);
}
public async Task<byte[]> DownloadFileAsync(ObjectId fileId)
{
return await _gridFS.DownloadAsBytesAsync(fileId);
}
}
Target Framework
- .NET 10
Dependencies
Indiko.Blocks.DataAccess.AbstractionsMongoDB.Driver(2.28+)MongoDB.Bson
License
See LICENSE file in the repository root.
Related Packages
Indiko.Blocks.DataAccess.Abstractions- Core data access abstractionsIndiko.Blocks.DataAccess.EntityFramework- EF Core implementationIndiko.Blocks.DataAccess.Marten- Marten implementation
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- Indiko.Blocks.DataAccess.Abstractions (>= 2.1.1)
- MongoDB.Driver (>= 3.5.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.1.1 | 25 | 12/2/2025 |
| 2.1.0 | 26 | 12/2/2025 |
| 2.0.0 | 302 | 9/17/2025 |
| 1.7.23 | 172 | 9/8/2025 |
| 1.7.22 | 169 | 9/8/2025 |
| 1.7.21 | 175 | 8/14/2025 |
| 1.7.20 | 173 | 6/23/2025 |
| 1.7.19 | 173 | 6/3/2025 |
| 1.7.18 | 167 | 5/29/2025 |
| 1.7.17 | 175 | 5/26/2025 |
| 1.7.15 | 131 | 4/12/2025 |
| 1.7.14 | 140 | 4/11/2025 |
| 1.7.13 | 142 | 3/29/2025 |
| 1.7.12 | 162 | 3/28/2025 |
| 1.7.11 | 167 | 3/28/2025 |
| 1.7.10 | 161 | 3/28/2025 |
| 1.7.9 | 164 | 3/28/2025 |
| 1.7.8 | 161 | 3/28/2025 |
| 1.7.5 | 180 | 3/17/2025 |
| 1.7.4 | 165 | 3/16/2025 |
| 1.7.3 | 165 | 3/16/2025 |
| 1.7.2 | 167 | 3/16/2025 |
| 1.7.1 | 191 | 3/11/2025 |
| 1.7.0 | 196 | 3/11/2025 |
| 1.6.8 | 193 | 3/11/2025 |
| 1.6.7 | 245 | 3/4/2025 |
| 1.6.6 | 134 | 2/26/2025 |
| 1.6.5 | 147 | 2/20/2025 |
| 1.6.4 | 143 | 2/20/2025 |
| 1.6.3 | 123 | 2/5/2025 |
| 1.6.2 | 120 | 1/24/2025 |
| 1.6.1 | 133 | 1/24/2025 |
| 1.6.0 | 139 | 1/16/2025 |
| 1.5.2 | 123 | 1/16/2025 |
| 1.5.1 | 148 | 11/3/2024 |
| 1.5.0 | 137 | 10/26/2024 |
| 1.3.2 | 137 | 10/24/2024 |
| 1.3.0 | 131 | 10/10/2024 |
| 1.2.5 | 144 | 10/9/2024 |
| 1.2.4 | 144 | 10/8/2024 |
| 1.2.1 | 134 | 10/3/2024 |
| 1.2.0 | 142 | 9/29/2024 |
| 1.1.1 | 135 | 9/23/2024 |
| 1.1.0 | 159 | 9/18/2024 |
| 1.0.33 | 145 | 9/15/2024 |
| 1.0.28 | 146 | 8/28/2024 |
| 1.0.27 | 175 | 8/24/2024 |
| 1.0.26 | 134 | 7/7/2024 |
| 1.0.25 | 149 | 7/6/2024 |
| 1.0.24 | 151 | 6/25/2024 |
| 1.0.23 | 157 | 6/1/2024 |
| 1.0.22 | 156 | 5/14/2024 |
| 1.0.21 | 152 | 5/14/2024 |
| 1.0.20 | 159 | 4/8/2024 |
| 1.0.19 | 149 | 4/3/2024 |
| 1.0.18 | 180 | 3/23/2024 |
| 1.0.17 | 177 | 3/19/2024 |
| 1.0.16 | 170 | 3/19/2024 |
| 1.0.15 | 147 | 3/11/2024 |
| 1.0.14 | 161 | 3/10/2024 |
| 1.0.13 | 163 | 3/6/2024 |
| 1.0.12 | 176 | 3/1/2024 |
| 1.0.11 | 170 | 3/1/2024 |
| 1.0.10 | 180 | 3/1/2024 |
| 1.0.9 | 168 | 3/1/2024 |
| 1.0.8 | 163 | 2/19/2024 |
| 1.0.7 | 164 | 2/17/2024 |
| 1.0.6 | 155 | 2/17/2024 |
| 1.0.5 | 153 | 2/17/2024 |
| 1.0.4 | 178 | 2/7/2024 |
| 1.0.3 | 161 | 2/6/2024 |
| 1.0.1 | 155 | 2/6/2024 |
| 1.0.0 | 206 | 1/9/2024 |
| 1.0.0-preview99 | 193 | 12/22/2023 |
| 1.0.0-preview98 | 143 | 12/21/2023 |
| 1.0.0-preview97 | 157 | 12/21/2023 |
| 1.0.0-preview96 | 141 | 12/20/2023 |
| 1.0.0-preview94 | 136 | 12/18/2023 |
| 1.0.0-preview93 | 211 | 12/13/2023 |
| 1.0.0-preview92 | 130 | 12/13/2023 |
| 1.0.0-preview91 | 153 | 12/12/2023 |
| 1.0.0-preview90 | 140 | 12/11/2023 |
| 1.0.0-preview89 | 159 | 12/11/2023 |
| 1.0.0-preview88 | 178 | 12/6/2023 |
| 1.0.0-preview87 | 166 | 12/6/2023 |
| 1.0.0-preview86 | 159 | 12/6/2023 |
| 1.0.0-preview85 | 153 | 12/6/2023 |
| 1.0.0-preview84 | 155 | 12/5/2023 |
| 1.0.0-preview83 | 158 | 12/5/2023 |
| 1.0.0-preview82 | 142 | 12/5/2023 |
| 1.0.0-preview81 | 147 | 12/4/2023 |
| 1.0.0-preview80 | 155 | 12/1/2023 |
| 1.0.0-preview77 | 152 | 12/1/2023 |
| 1.0.0-preview76 | 139 | 12/1/2023 |
| 1.0.0-preview75 | 140 | 12/1/2023 |
| 1.0.0-preview74 | 165 | 11/26/2023 |
| 1.0.0-preview73 | 173 | 11/7/2023 |
| 1.0.0-preview72 | 152 | 11/6/2023 |
| 1.0.0-preview71 | 158 | 11/3/2023 |
| 1.0.0-preview70 | 146 | 11/2/2023 |
| 1.0.0-preview69 | 146 | 11/2/2023 |
| 1.0.0-preview68 | 149 | 11/2/2023 |
| 1.0.0-preview67 | 144 | 11/2/2023 |
| 1.0.0-preview66 | 123 | 11/2/2023 |
| 1.0.0-preview65 | 154 | 11/2/2023 |
| 1.0.0-preview64 | 157 | 11/2/2023 |
| 1.0.0-preview63 | 143 | 11/2/2023 |
| 1.0.0-preview62 | 149 | 11/1/2023 |
| 1.0.0-preview61 | 142 | 11/1/2023 |
| 1.0.0-preview60 | 138 | 11/1/2023 |
| 1.0.0-preview59 | 141 | 11/1/2023 |
| 1.0.0-preview58 | 146 | 10/31/2023 |
| 1.0.0-preview57 | 142 | 10/31/2023 |
| 1.0.0-preview56 | 152 | 10/31/2023 |
| 1.0.0-preview55 | 142 | 10/31/2023 |
| 1.0.0-preview54 | 145 | 10/31/2023 |
| 1.0.0-preview53 | 133 | 10/31/2023 |
| 1.0.0-preview52 | 145 | 10/31/2023 |
| 1.0.0-preview51 | 138 | 10/31/2023 |
| 1.0.0-preview50 | 151 | 10/31/2023 |
| 1.0.0-preview48 | 156 | 10/31/2023 |
| 1.0.0-preview46 | 143 | 10/31/2023 |
| 1.0.0-preview45 | 142 | 10/31/2023 |
| 1.0.0-preview44 | 142 | 10/31/2023 |
| 1.0.0-preview43 | 138 | 10/31/2023 |
| 1.0.0-preview42 | 154 | 10/30/2023 |
| 1.0.0-preview41 | 156 | 10/30/2023 |
| 1.0.0-preview40 | 152 | 10/27/2023 |
| 1.0.0-preview39 | 152 | 10/27/2023 |
| 1.0.0-preview38 | 143 | 10/27/2023 |
| 1.0.0-preview37 | 145 | 10/27/2023 |
| 1.0.0-preview36 | 148 | 10/27/2023 |
| 1.0.0-preview35 | 144 | 10/27/2023 |
| 1.0.0-preview34 | 138 | 10/27/2023 |
| 1.0.0-preview33 | 153 | 10/26/2023 |
| 1.0.0-preview32 | 160 | 10/26/2023 |
| 1.0.0-preview31 | 149 | 10/26/2023 |
| 1.0.0-preview30 | 156 | 10/26/2023 |
| 1.0.0-preview29 | 158 | 10/26/2023 |
| 1.0.0-preview28 | 157 | 10/26/2023 |
| 1.0.0-preview27 | 158 | 10/26/2023 |
| 1.0.0-preview26 | 159 | 10/25/2023 |
| 1.0.0-preview25 | 161 | 10/23/2023 |
| 1.0.0-preview24 | 143 | 10/23/2023 |
| 1.0.0-preview23 | 153 | 10/23/2023 |
| 1.0.0-preview22 | 139 | 10/23/2023 |
| 1.0.0-preview21 | 155 | 10/23/2023 |
| 1.0.0-preview20 | 160 | 10/20/2023 |
| 1.0.0-preview19 | 156 | 10/19/2023 |
| 1.0.0-preview18 | 166 | 10/18/2023 |
| 1.0.0-preview16 | 163 | 10/11/2023 |
| 1.0.0-preview14 | 142 | 10/10/2023 |
| 1.0.0-preview13 | 151 | 10/10/2023 |
| 1.0.0-preview12 | 156 | 10/9/2023 |
| 1.0.0-preview11 | 151 | 10/9/2023 |
| 1.0.0-preview101 | 143 | 1/5/2024 |