mongodb-integration

>

abpframework/abp-skills2 installsMITSynced Aug 26

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: mongodb-integration
description: >
license: MIT
---

# ABP MongoDB Integration

Guidance for the MongoDB data-access layer of an ABP solution. Types live in `Volo.Abp.MongoDB`. The integration lives in the `*.MongoDB` project; repository interfaces belong in the `*.Domain` project.

## When to Use

- Defining an `AbpMongoDbContext` and exposing collections as `IMongoCollection<T>`.
- Naming collections with `[MongoCollection]` and mapping entities in `CreateModel`.
- Registering the DbContext and repositories with `AddMongoDbContext`.
- Writing a custom repository over `MongoDbRepository<TMongoDbContext, TEntity, TKey>`.
- Reaching another collection via `IMongoDbContextProvider<TMongoDbContext>`, or dropping to the native driver with `GetCollectionAsync()` / `GetAggregateAsync()`.

## When Not to Use

- **EF Core data access, `OnModelCreating`, or `dotnet ef` migrations** — use the **ef-core-integration** skill instead.
- **Transaction / Unit of Work boundaries** — use **manage-units-of-work**.
- **Soft-delete / multi-tenant / custom filters** (including `MongoDbRepositoryFilterer`) — use **apply-data-filters**.
- **Optimistic concurrency** — use **handle-optimistic-concurrency**.
- **Connection-string configuration** — use **configure-connection-strings**; **data seeding** — use **seed-application-data**.

## How it works

### DbContext

Derive from `AbpMongoDbContext`. Expose each collection as an `IMongoCollection<T>` property and mark it with `[MongoCollection]` (from `Volo.Abp.MongoDB`) to name the collection. Attach the module's model configuration by overriding `CreateModel`.

```csharp
[ConnectionStringName("Default")]
public class MyProjectMongoDbContext : AbpMongoDbContext
{
    [MongoCollection("AppBooks")]
    public IMongoCollection<Book> Books => Collection<Book>();

    protected override void CreateModel(IMongoModelBuilder modelBuilder)
    {
        base.CreateModel(modelBuilder);

        modelBuilder.Entity<Book>(b =>
        {
            b.CollectionName = "AppBooks";
        });
    }
}
```

- `[MongoCollection]` sets the collection name (`CollectionName` on the attribute); without it the DbContext collection property name is used (e.g. the `Books` property maps to a `Books` collection).
- `Collection<T>()` (defined on `AbpMongoDbContext`) returns the underlying `IMongoCollection<T>`.
- `IMongoModelBuilder.Entity<TEntity>(...)` maps an entity; set `CollectionName`, indexes, or a BSON class map there.
- The base `AbpMongoDbContext.CreateModel` is empty; calling `base.CreateModel(modelBuilder)` is a harmless convention, not a requirement that wires up ABP's entities.

### Module ConfigureXxx() convention

Reusable modules ship a `builder.Configure<Module>()` extension on `IMongoModelBuilder`. Call them inside `CreateModel`:

```csharp
modelBuilder.ConfigurePermissionManagement();
modelBuilder.ConfigureSettingManagement();
```

### Registration

Register in your `*.MongoDB` module's `ConfigureServices` via `AddMongoDbContext<TMongoDbContext>`:

```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
    context.Services.AddMongoDbContext<MyProjectMongoDbContext>(options =>
    {
        options.AddDefaultRepositories(includeAllEntities: true);

        // Custom repository override
        options.AddRepository<Book, MongoDbBookRepository>();
    });
}
```

The registration builder shares the same API as EF Core: `AddDefaultRepositories`, `AddDefaultRepository<TEntity>()`, `AddRepository<TEntity, TRepository>()`.

### Custom repositories

Declare the interface in the **Domain** project (same as EF Core — `IRepository<TEntity, TKey>`):

```csharp
public interface IBookRepository : IRepository<Book, Guid>
{
    Task<List<Book>> GetListByAuthorAsync(Guid authorId);
}
```

`IRepository` is the right base inside a **final application**. For a **reusable module** published for other apps, extend `IBasicRepository<Book, Guid>` (or `IReadOnlyBasicRepository`) instead, so consumers aren't coupled to a provider's `IQueryable` (see use-abp-repositories).

Implement in the **MongoDB** project by deriving from `MongoDbRepository<TMongoDbContext, TEntity, TKey>`:

```csharp
public class MongoDbBookRepository
    : MongoDbRepository<MyProjectMongoDbContext, Book, Guid>, IBookRepository
{
    public MongoDbBookRepository(IMongoDbContextProvider<MyProjectMongoDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }

    public async Task<List<Book>> GetListByAuthorAsync(Guid authorId)
    {
        var queryable = await GetQueryableAsync();
        return await queryable.Where(b => b.AuthorId == authorId).ToListAsync();
    }
}
```

#### Querying inside a repository

- `GetQueryableAsync()` → `IQueryable<TEntity>` (LINQ over the collection; the driver translates it).
- `GetCollectionAsync()` → the raw `IMongoCollection<TEntity>` for native driver operations (aggregation, bulk writes).
- `GetAggregateAsync()` → an `IAggregateFluent<TEntity>` for aggregation pipelines.

The base repository already applies ABP's global filters (soft-delete, multi-tenancy) to `GetQueryableAsync()`; going through the raw collection bypasses them.

#### DbContext provider

Inject `IMongoDbContextProvider<TMongoDbContext>` to reach the DbContext directly and get another collection:

```csharp
var dbContext = await _dbContextProvider.GetDbContextAsync();
var authors = dbContext.Collection<Author>();
```

### Differences vs EF Core

- **No migrations.** MongoDB is schemaless — there is no `dotnet ef migrations` step. The startup template's schema migrator (`MongoDb...DbSchemaMigrator`) instead calls `InitializeCollections`, which creates the collections and any configured indexes; the `DbMigrator` console app (if present) also runs `IDataSeeder` to seed data.
- **No relational joins.** You cannot compose cross-collection joins the way you would with EF Core navigation properties. Load related aggregates with separate queries, or model them within the aggregate. Use `GetAggregateAsync()` / `$lookup` only when a real aggregation pipeline is needed.
- **Attribute for naming is `[MongoCollection]`**, not table mapping.
- Everything else — repository interfaces in Domain, `AddDefaultRepositories`, custom repository pattern, `[ConnectionStringName]` — mirrors the EF Core integration, so application/domain code stays provider-agnostic.

## Validation

- The `*.MongoDB` project references `Volo.Abp.MongoDB`; the DbContext derives from `AbpMongoDbContext` and carries `[ConnectionStringName]`.
- Injecting the default `IRepository<Book, Guid>` (or your `IBookRepository`) resolves after `AddMongoDbContext` registration — confirm the app boots and the repository is available.
- Queried results honor ABP's global filters when you go through `GetQueryableAsync()`; a native `GetCollectionAsync()` query returns unfiltered rows.
- The Domain/Application projects do not reference `Volo.Abp.MongoDB` — repository interfaces stay provider-agnostic.

## Common Pitfalls

- **Going through the raw collection (`GetCollectionAsync()`) unexpectedly bypasses ABP's global filters** (soft-delete, multi-tenancy). Use `GetQueryableAsync()` unless you deliberately need native driver operations.
- **Expecting relational joins** — MongoDB has none; load related aggregates with separate queries or model them within the aggregate, and use `$lookup`/`GetAggregateAsync()` only for real aggregation pipelines.
- **Expecting `dotnet ef migrations`** — MongoDB has none. The template's schema migrator calls `InitializeCollections` to create collections and configured indexes, and the `DbMigrator` (if present) additionally seeds data.
- **Omitting `[MongoCollection]`** — the collection is then named after the property, which may not match your intended collection name.

More Database skills

← All Database skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY