Skip to content

Data Providers MongoDB

quyvu edited this page Oct 14, 2026 · 3 revisions

MongoDB Provider

Integrate FxMap with MongoDB for seamless NoSQL document database access with aggregation pipeline optimization.

Installation

dotnet add package FxMap.MongoDb

Or via Package Manager Console:

Install-Package FxMap.MongoDb

Configuration

Register 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();

Isolate expression errors

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.

Document Models & Entity Configs

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>();
    }
}

How It Works

FxMap.MongoDb translates your expressions into MongoDB aggregation pipelines:

Your Profile

public class OrderResponseProfile : ProfileOf<OrderResponse>
{
    protected override void Configure()
    {
        UseDistributedKey<UserDistributedKey>()
            .Of(x => x.UserId)
            .For(x => x.CountryName, "Province.Country.Name");
    }
}

Generated Pipeline

[
  { $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"
  }}
]

Complete Example

// 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"
// }

Working with Arrays

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)");
    }
}

Performance Benefits

Optimized Aggregations

FxMap generates efficient aggregation pipelines with $lookup, $unwind, and $project stages optimized for your expressions.

Selective Projection

Only the fields needed by your DTO are retrieved from MongoDB, reducing network transfer and improving performance.

Query Batching

Multiple queries are batched together when possible to minimize database round-trips.

Best Practices

Use Indexes

Create indexes on fields used in lookups (foreign keys) and filters to improve query performance.

ObjectId vs String

Use BsonRepresentation(BsonType.ObjectId) for string properties that store ObjectIds for proper BSON serialization.

Collection Registration

Register all collections that will be accessed by FxMap during startup for proper configuration.

Version Compatibility

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.

Clone this wiki locally