# Mongo Db

## Description

MongoDB is used as a **Document DB provider** through the shared Flex document-store abstraction (`IFlexDocumentStore`). Generated code keeps your application code provider-agnostic: your queries/handlers talk to `IFlexDocumentStore`, and the provider wiring decides whether that’s MongoDB, Cosmos DB, Dynamo DB, etc.

## Important Concepts

* **Query/Handler pattern**: reads happen in `.../Queries`, writes happen in `.../Handlers`.
* **AppContext is mandatory**: always call `dto.GetAppContext()` in queries/handlers (the templates mark it as “do not remove”).
* **Provider is hidden behind interfaces**: your code depends on `IFlexDocumentStore`, not Mongo SDK types.

## Configuration in DI (where to add)

Provider wiring is generated in your Infrastructure project (under a `...DataStoreProviders/Document/MongoDb` folder). You typically do **not** register individual queries/handlers here — Flex generates and wires those.

If you are wiring Mongo manually, add the **document-store provider** registration where you configure infrastructure services (often in `Program.cs` or an Infrastructure DI module):

```csharp
// Infrastructure (example)
services.AddFlexMongoDocumentStore<InvoiceDocument>(
    configuration,
    collectionName: "Invoices");
```

> Where to put business registrations? Use your EndPoints “common configs” area (like `OtherApplicationServicesConfig`) for registering *your own* application services. The MongoDB provider itself is registered in Infrastructure.

## appsettings.json

```json
{
	"FlexBase": {
		"DataStores": {
			"Document": {
				"MongoDb": {
					"ConnectionString": "mongodb://...",
					"DatabaseName": "{YourApplication}",
					"EnableSSL": true,
					"ConnectionTimeout": "00:00:30",
					"MaxConnectionPoolSize": 100
				}
			}
		}
  }
}
```

## Examples (from the generated templates)

The generator uses the same shape for all Document DB providers; only the provider wiring changes.

### Handler example (Create)

This follows the template in `PostBusHandler/DocumentDataStore/DocumentStoreHandlerTemplate_Create.cs`.

```csharp
using Microsoft.Extensions.Logging;
using Sumeru.Flex;
using System.Threading.Tasks;

public interface ICreateInvoiceHandler : IAmFlexCommandHandler<CreateInvoiceCommand> { }

public partial class CreateInvoiceHandler : ICreateInvoiceHandler
{
	protected string EventCondition = "";

	protected readonly ILogger<CreateInvoiceHandler> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexDocumentStore _documentStore;
	protected readonly IInvoiceMapper _mapper;

	protected InvoiceDocument? _model;
	protected FlexAppContextBridge? _flexAppContext;

	public CreateInvoiceHandler(
		ILogger<CreateInvoiceHandler> logger,
		IFlexHost flexHost,
		IFlexDocumentStore documentStore,
		IInvoiceMapper mapper)
	{
		_logger = logger;
		_flexHost = flexHost;
		_documentStore = documentStore;
		_mapper = mapper;
	}

	public virtual async Task Execute(CreateInvoiceCommand cmd, IFlexServiceBusContext serviceBusContext)
	{
		_flexAppContext = cmd.Dto.GetAppContext(); // do not remove

		_model = _mapper.MapToDocument(cmd.Dto);
		var created = await _documentStore.CreateAsync<InvoiceDocument>(_model);

		// TODO: set EventCondition based on business logic (example: CONDITION_ONSUCCESS)
		await this.Fire(EventCondition, serviceBusContext);
	}
}
```

### Query example (Get-by-id)

This follows the template in `Query/DocumentDataStore/DocumentStoreQueryGetByIdTemplate.cs`.

```csharp
using Microsoft.Extensions.Logging;
using Sumeru.Flex;
using System;
using System.Threading.Tasks;

public class GetInvoiceById : FlexiQueryBridgeAsync<InvoiceDto>
{
	protected readonly ILogger<GetInvoiceById> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexDocumentStore _documentStore;
	protected GetInvoiceByIdParams _params;
	protected FlexAppContextBridge _flexAppContext;

	public GetInvoiceById(ILogger<GetInvoiceById> logger, IFlexHost flexHost, IFlexDocumentStore documentStore)
	{
		_logger = logger;
		_flexHost = flexHost;
		_documentStore = documentStore;
	}

	public virtual GetInvoiceById AssignParameters(GetInvoiceByIdParams @params)
	{
		_params = @params;
		return this;
	}

	public virtual async Task<InvoiceDto?> Fetch()
	{
		_flexAppContext = _params.GetAppContext();

		var doc = await _documentStore.GetByIdAsync<InvoiceDocument>(_params.Id);
		return doc == null ? null : new InvoiceDto { Id = doc.Id, Status = doc.Status };
	}
}

public class GetInvoiceByIdParams : DtoBridge
{
	public Guid Id { get; set; }
}
```

### Query example (Simple list)

This follows the template in `Query/DocumentDataStore/DocumentStoreQueryGetEnumerableTemplate.cs`.

```csharp
using Microsoft.Extensions.Logging;
using Sumeru.Flex;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;

public class ListInvoices : FlexiQueryEnumerableBridgeAsync<InvoiceDto>
{
	protected readonly ILogger<ListInvoices> _logger;
	protected readonly IFlexHost _flexHost;
	protected readonly IFlexDocumentStore _documentStore;
	protected ListInvoicesParams _params;
	protected FlexAppContextBridge _flexAppContext;

	public ListInvoices(ILogger<ListInvoices> logger, IFlexHost flexHost, IFlexDocumentStore documentStore)
	{
		_logger = logger;
		_flexHost = flexHost;
		_documentStore = documentStore;
	}

	public virtual ListInvoices AssignParameters(ListInvoicesParams @params)
	{
		_params = @params;
		return this;
	}

	public virtual async Task<IEnumerable<InvoiceDto>> Fetch()
	{
		_flexAppContext = _params.GetAppContext();

		Expression<Func<InvoiceDocument, bool>> filter = x => x.CustomerId == _params.CustomerId;
		var docs = await _documentStore.GetManyAsync<InvoiceDocument>(filter);

		// TODO: map documents to DTOs
		return docs == null
			? Array.Empty<InvoiceDto>()
			: docs.Select(d => new InvoiceDto { Id = d.Id, Status = d.Status });
	}
}

public class ListInvoicesParams : DtoBridge
{
	public string CustomerId { get; set; } = "";
}
```

## Provider-specific considerations

* **Replica sets**: prefer replica-set aware connection strings for failover.
* **Indexing**: define the “must have” indexes for your hot queries in configuration so deployments stay consistent.
* **Read preferences**: align read preference with your consistency needs (primary vs preferred).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flexbase.in/data-and-providers/data-stores/document-db/mongo-db.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
