Skip to content

Features

Aryeh Citron edited this page May 12, 2026 · 2 revisions

Features

CRUD Operations

Full support for all typed and BsonDocument operations:

  • InsertOne / InsertMany with ordered/unordered modes
  • Find with filter, sort, skip, limit, projection
  • UpdateOne / UpdateMany with upsert support
  • ReplaceOne with upsert support
  • DeleteOne / DeleteMany
  • FindOneAndDelete / FindOneAndReplace / FindOneAndUpdate (with ReturnDocument.Before / After)
  • BulkWrite with all write model types
  • CountDocuments / EstimatedDocumentCount
  • Distinct
  • DistinctMany (not yet implemented — throws NotSupportedException)

Change Streams

var cursor = await collection.WatchAsync();
// Insert/Update/Delete operations fire change events
while (await cursor.MoveNextAsync())
{
    foreach (var change in cursor.Current)
    {
        Console.WriteLine($"{change.OperationType}: {change.FullDocument}");
    }
}
  • Collection-level, database-level, and client-level Watch()
  • Resume tokens for checkpoint-based resumption
  • OperationType: Insert, Update, Replace, Delete
  • FullDocument and FullDocumentBeforeChange fields
  • Pipeline filtering on change events

Transactions

using var session = await client.StartSessionAsync();
session.StartTransaction();

await collection.InsertOneAsync(session, new Order { Total = 100 });
await collection.UpdateOneAsync(session, filter, update);

await session.CommitTransactionAsync();
// Or: await session.AbortTransactionAsync();
  • Snapshot isolation within transactions
  • Automatic rollback on abort
  • Session-scoped operations

Indexes

// Unique index (enforced)
await collection.Indexes.CreateOneAsync(
    new CreateIndexModel<Order>(
        Builders<Order>.IndexKeys.Ascending(o => o.Email),
        new CreateIndexOptions { Unique = true }));

// Compound unique
await collection.Indexes.CreateOneAsync(
    new CreateIndexModel<Order>(
        Builders<Order>.IndexKeys.Ascending(o => o.Name).Ascending(o => o.Email),
        new CreateIndexOptions { Unique = true }));

// Sparse + unique
await collection.Indexes.CreateOneAsync(
    new CreateIndexModel<Order>(
        Builders<Order>.IndexKeys.Ascending(o => o.Email),
        new CreateIndexOptions { Unique = true, Sparse = true }));

// List indexes
var indexes = await collection.Indexes.ListAsync();

Supported index types:

  • Unique — Enforced on all write operations
  • Compound — Multi-field uniqueness enforcement
  • Sparse — Documents missing the indexed field are excluded from uniqueness
  • Partial Filter — Unique constraint only applies to documents matching the filter
  • TTL — Documents expire after ExpireAfterSeconds (see below)
  • Text — Accepted, used for $text filter
  • 2dsphere — Accepted, used for geospatial queries
  • Hashed — Accepted (no sharding simulation)
  • Wildcard — Accepted

TTL / Expiration

await collection.Indexes.CreateOneAsync(
    new CreateIndexModel<Session>(
        Builders<Session>.IndexKeys.Ascending(s => s.CreatedAt),
        new CreateIndexOptions { ExpireAfter = TimeSpan.FromHours(24) }));
  • TTL indexes automatically expire documents based on a date field
  • Lazy eviction: expired documents are removed from the store when queries execute
  • Documents with missing or non-date TTL fields never expire
  • Array fields use the earliest date for expiration calculation
  • ExpireAfterSeconds = 0 means documents expire at the exact field value time

Schema Validation

await database.CreateCollectionAsync("orders", new CreateCollectionOptions
{
    Validator = new BsonDocument("$jsonSchema", new BsonDocument
    {
        { "bsonType", "object" },
        { "required", new BsonArray { "total", "status" } },
        { "properties", new BsonDocument
            {
                { "total", new BsonDocument("bsonType", "double") },
                { "status", new BsonDocument("enum", new BsonArray { "pending", "shipped", "completed" }) }
            }
        }
    })
});

Supported $jsonSchema constraints: required, bsonType, minimum, maximum, minLength, maxLength, pattern, enum, minItems, maxItems, additionalProperties.

Collation

Collection and query-level collation is accepted and stored. Sorting uses .NET CultureInfo for culture-aware comparison.

GridFS

var bucket = new InMemoryGridFSBucket(database, new GridFSBucketOptions { BucketName = "fs" });

// Upload
var id = await bucket.UploadFromBytesAsync("file.txt", fileBytes);

// Download
var bytes = await bucket.DownloadAsBytesAsync(id);

// Find
var files = await bucket.FindAsync(Builders<GridFSFileInfo>.Filter.Eq("filename", "file.txt"));

// Delete / Rename
await bucket.DeleteAsync(id);
await bucket.RenameAsync(id, "new-name.txt");

Views

await database.CreateViewAsync<BsonDocument, BsonDocument>(
    "activeOrders",
    "orders",
    PipelineDefinition<BsonDocument, BsonDocument>.Create(
        new BsonDocument("$match", new BsonDocument("status", "active"))
    ));

var view = database.GetCollection<BsonDocument>("activeOrders");
var results = await view.Find(FilterDefinition<BsonDocument>.Empty).ToListAsync();

Capped Collections

await database.CreateCollectionAsync("logs", new CreateCollectionOptions
{
    Capped = true,
    MaxDocuments = 1000,
    MaxSize = 1048576 // 1MB
});
  • FIFO eviction when maxDocuments or maxSize is exceeded
  • Insertion order preserved
  • Cannot delete from capped collections
  • Tailable cursor support (CursorType.Tailable and CursorType.TailableAwait)

Fault Injection

var collection = result.Collection as InMemoryMongoCollection<Order>;
collection!.FaultInjector = (operation, doc) =>
{
    if (operation == "insert")
        throw new InvalidOperationException("Simulated insert failure");
};

Supported operations: insert, find, update, delete, aggregate

Operation Logging

var collection = result.Collection as InMemoryMongoCollection<Order>;
var log = collection!.OperationLog;

// After some operations...
var inserts = log.GetByType("InsertOne");
var allOps = log.GetAll();
log.Clear();

Each OperationRecord contains: Type, Filter, Update, Document, Pipeline, Timestamp.

RunCommand Support

The following database commands are supported via database.RunCommand():

ping, buildInfo, serverStatus, hostInfo, connectionStatus, listCommands, collStats, dbStats, count, distinct, create, drop, createIndexes, dropIndexes, aggregate, explain

LINQ

var queryable = collection.AsQueryable();
var results = queryable.Where(o => o.Total > 100).OrderBy(o => o.Total).ToList();

See LINQ Support for details.

See Also

Clone this wiki locally