Repository navigation
Data Providers MongoDB
Integrate FxMap with MongoDB for seamless NoSQL document database access with aggregation pipeline optimization.
dotnet add package FxMap.MongoDbOr via Package Manager Console:
Install-Package FxMap.MongoDbRegister FxMap.MongoDb in your Program.cs and specify which collections to use:
using FxMap;
using FxMap.MongoDb;
using MongoDB.Driver;
var builder = WebApplication.CreateBuilder(args);
// Configure MongoDB client
var mongoClient = new MongoClient("mongodb://localhost:27017");
var database = mongoClient.GetDatabase("MyDatabase");
// Get collections
var userCollection = database.GetCollection<User>("users");
var orderCollection = database.GetCollection<Order>("orders");
var provinceCollection = database.GetCollection<Province>("provinces");
// Add FxMap with MongoDB provider
builder.Services.AddFxMap(cfg =>
{
cfg.AddEntitiesFromAssemblyContaining<SomeEntityAssemblyMarker>();
cfg.AddProfilesFromAssemblyContaining<SomeProfileAssemblyMarker>();
})
.AddMongoDb(cfg =>
{
cfg.AddCollection(userCollection);
cfg.AddCollection(orderCollection);
cfg.AddCollection(provinceCollection);
});
var app = builder.Build();
app.Run();Since 4.1.3, one expression that cannot be built does not have to fail the whole request. With IsolateExpressionErrors() the provider answers the other expressions and reports the broken ones in the response:
.AddMongoDb(c =>
{
c.AddCollection(userCollection);
c.IsolateExpressionErrors();
});It works as in the Entity Framework Core provider: each error is reported once, the value of the broken expression is null, and the service that asked throws with ThrowIfException() or logs a warning. In MongoDB an unknown property is not an error (a missing field is null); syntax errors and unknown functions are.
Define your MongoDB document models and their FxMap entity configs:
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
// Domain models (clean, no attributes)
public class User
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
[BsonRepresentation(BsonType.ObjectId)]
public string ProvinceId { get; set; }
}
public class Province
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Name { get; set; }
[BsonRepresentation(BsonType.ObjectId)]
public string CountryId { get; set; }
}
public class Country
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
// Distributed keys
public sealed class UserDistributedKey : IDistributedKey;
public sealed class ProvinceDistributedKey : IDistributedKey;
public sealed class CountryDistributedKey : IDistributedKey;
// Entity configs (FluentAPI)
public class UserConfig : EntityConfigureOf<User>
{
protected override void Configure()
{
Id(x => x.Id);
DefaultProperty(x => x.Name);
UseDistributedKey<UserDistributedKey>();
}
}
public class ProvinceConfig : EntityConfigureOf<Province>
{
protected override void Configure()
{
Id(x => x.Id);
DefaultProperty(x => x.Name);
UseDistributedKey<ProvinceDistributedKey>();
}
}
public class CountryConfig : EntityConfigureOf<Country>
{
protected override void Configure()
{
Id(x => x.Id);
DefaultProperty(x => x.Name);
UseDistributedKey<CountryDistributedKey>();
}
}FxMap.MongoDb translates your expressions into MongoDB aggregation pipelines:
public class OrderResponseProfile : ProfileOf<OrderResponse>
{
protected override void Configure()
{
UseDistributedKey<UserDistributedKey>()
.Of(x => x.UserId)
.For(x => x.CountryName, "Province.Country.Name");
}
}[
{ $match: { _id: ObjectId(...) } },
{ $lookup: {
from: "provinces",
localField: "ProvinceId",
foreignField: "_id",
as: "Province"
}},
{ $unwind: "$Province" },
{ $lookup: {
from: "countries",
localField: "Province.CountryId",
foreignField: "_id",
as: "Country"
}},
{ $unwind: "$Country" },
{ $project: {
CountryName: "$Country.Name"
}}
]// DTO
public class UserDetailResponse
{
public string UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
// Profile
public class UserDetailResponseProfile : ProfileOf<UserDetailResponse>
{
protected override void Configure()
{
UseDistributedKey<UserDistributedKey>()
.Of(x => x.UserId)
.For(x => x.Name)
.For(x => x.Email, "Email")
.For(x => x.Phone, "PhoneNumber");
}
}
// Service using FxMap with MongoDB
public class UserService
{
private readonly IDistributedMapper _mapper;
public UserService(IDistributedMapper mapper)
{
_mapper = mapper;
}
public async Task<UserDetailResponse> GetUserDetailsAsync(string userId)
{
var response = new UserDetailResponse { UserId = userId };
await _mapper.MapDataAsync(response);
return response;
}
}
// Usage
var userService = app.Services.GetRequiredService<UserService>();
var userDetails = await userService.GetUserDetailsAsync("507f1f77bcf86cd799439011");
// Result:
// {
// "UserId": "507f1f77bcf86cd799439011",
// "Name": "John Doe",
// "Email": "john@example.com",
// "Phone": "+1234567890"
// }FxMap seamlessly handles MongoDB array operations:
// Document model with array
public class Country
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Name { get; set; }
public List<Province> Provinces { get; set; }
}
// Entity config
public class CountryConfig : EntityConfigureOf<Country>
{
protected override void Configure()
{
Id(x => x.Id);
DefaultProperty(x => x.Name);
UseDistributedKey<CountryDistributedKey>();
}
}
// DTO and profile accessing array elements
public class CountryResponse
{
public string CountryId { get; set; }
public string FirstProvinceName { get; set; }
public string FirstProvinceByName { get; set; }
public List<ProvinceDto> LargeProvinces { get; set; }
}
public class CountryResponseProfile : ProfileOf<CountryResponse>
{
protected override void Configure()
{
UseDistributedKey<CountryDistributedKey>()
.Of(x => x.CountryId)
.For(x => x.FirstProvinceName, "Provinces:first.Name")
.For(x => x.FirstProvinceByName, "Provinces:orderBy(Name):first.Name")
.For(x => x.LargeProvinces, "Provinces:where(Population > 1000000)");
}
}FxMap generates efficient aggregation pipelines with $lookup, $unwind, and $project stages optimized for your expressions.
Only the fields needed by your DTO are retrieved from MongoDB, reducing network transfer and improving performance.
Multiple queries are batched together when possible to minimize database round-trips.
Create indexes on fields used in lookups (foreign keys) and filters to improve query performance.
Use BsonRepresentation(BsonType.ObjectId) for string properties that store ObjectIds for proper BSON serialization.
Register all collections that will be accessed by FxMap during startup for proper configuration.
Ensure all FxMap packages (FxMap, FxMap.MongoDb, and any transport packages) have matching version numbers for compatibility.
:orderBy uses $sortArray, which needs MongoDB 5.2 or newer: on an older server it fails. The keys of :orderBy are named as written in the expression, so a field renamed with [BsonElement] is not translated. The driver is MongoDB.Driver 3.9.0 or newer since 4.1.4.
Source: https://fxmapper.net/docs/data-providers/mongodb/ — the website is always the most up to date version.
Introduction
Getting Started
Configuration
- Service Registration
- Entities & Profiles
- Handlers
- Pipelines
- Strongly Typed IDs
- Error Handling
- Retry Policy
- Supervisor
- Telemetry
- Kestrel (HTTP/2)
- Analyzers
Expressions
- Overview
- Property Access
- Filters, Sorting & Paging
- Functions
- Aggregations
- Projections
- Coalesce & Ternary
- GroupBy
Data Providers
Transports
Integrations
Quality
AI Assistants
Migration
Release Notes