Tenowg.MongoObjects
0.3.1-beta
dotnet add package Tenowg.MongoObjects --version 0.3.1-beta
NuGet\Install-Package Tenowg.MongoObjects -Version 0.3.1-beta
<PackageReference Include="Tenowg.MongoObjects" Version="0.3.1-beta" />
<PackageVersion Include="Tenowg.MongoObjects" Version="0.3.1-beta" />
<PackageReference Include="Tenowg.MongoObjects" />
paket add Tenowg.MongoObjects --version 0.3.1-beta
#r "nuget: Tenowg.MongoObjects, 0.3.1-beta"
#:package Tenowg.MongoObjects@0.3.1-beta
#addin nuget:?package=Tenowg.MongoObjects&version=0.3.1-beta&prerelease
#tool nuget:?package=Tenowg.MongoObjects&version=0.3.1-beta&prerelease
MongoObject
A modern MongoDB ODM for .NET 10 with source generation and automatic change tracking.
Overview
MongoObject is a source-generated MongoDB ODM for modern .NET.
Instead of writing string-based queries, update definitions, projection definitions, indexes, and validation schemas manually, MongoObject generates strongly typed APIs directly from your POCO models at compile time.
Resulting in:
- Compile-time validation instead of runtime errors
- Automatic change tracking
- Minimal update payloads
- Zero reflection-based mapping
- Less boilerplate than using MongoDB.Driver directly
MongoObject bridges the gap between MongoDB's document model and modern .NET development. Using Roslyn source generators and C# 14 partial properties, it provides an intuitive, inspired by EF Core's change tracking, experience for working with MongoDB documents.
Why
I think this explains it all:
"MongoObject wasn't built because MongoDB.Driver is bad. It was built because even experienced MongoDB developers have to stop and think every time they write a
Builders<T>.Filterquery. The API is powerful but not discoverable. MongoObject makes the right thing the obvious thing."
Key Features
- 🚀 Source Generation - Automatic implementation via
[MongoObject]attribute - 📊 Change Tracking - Automatic property change detection for efficient updates
- 📝 Metadata Support - Separate metadata types for versioning, timestamps, and ownership
- 🔍 Type-Safe Queries - Generated search classes for compile-time query validation
- 🎯 Projections - Selective field retrieval with
[ProjectValue]attribute - 🔒 Distributed Locking - Document-level concurrency control
- ⚡ Caching - Built-in memory caching with configurable expiration
- 👁️ Change Streams - Real-time MongoDB change monitoring
- Cli Based Migration Support - run a migration tool to help build, validate, and rename properties
- Vector Search Ingration - Vector Search is a built in feature, enabled by adding a few Attributes, described more in the full documentation.
Design Goals
MongoObject is designed around a few principles:
- Compile-time safety over runtime configuration
- POCO-first development
- Minimal MongoDB payloads
- Zero boilerplate
- Source generation instead of reflection
- Native MongoDB features without hiding MongoDB itself
Installation
The
Tenowg.MongoObjectspackage is currently in active development.
// install the main package
dotnet add package Tenowg.MongoObjects --prerelease
// install the Cli
dotnet tool install -g Tenowg.MongoObjects.CliTool
OR
# Clone the repository
git clone https://github.com/tenowg/MongoObject.git
# Add project reference to your .csproj
<ProjectReference Include="path/to/MongoObject.Core/MongoObject.Core.csproj" />
Quick Start
1. Define Your Document
using MongoObject.Core.Attributes;
// Define optional metadata type
public partial record UserMeta
{
public string? CreatedBy { get; set; }
public string? Department { get; set; }
}
// Define your document class
[MongoObject(
CollectionName = "Users",
DatabaseName = "MyApp",
MetadataType = typeof(UserMeta)
)]
public partial class User
{
public partial string Name { get; set; }
public partial string Email { get; set; }
public partial int Age { get; set; }
public partial Address Address { get; set; }
public partial List<string> Roles { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
2. Register in Dependency Injection
using MongoObject.Core.Extensions;
var builder = Host.CreateDefaultBuilder(args)
.ConfigureServices(config, (_, services) =>
{
services.AddMongoObject(config, (builder, options) =>
{
options.ConnectionString = apiKey;
options.DatabaseName = "mydatabase";
builder.AddWatchStream()
.RegisterDocumentsProjectName();
});
});
RegisterDocumentsProjectName is a source generated discovery class, calling it will register all POCO class marked with
[MongoObject]with DI. Just need to change ProjectName to yourProjectName. This will also handle POCO's defined in other libraries such as shared data libraries. Just need to add an additional .RegisterDocumentsSharedLibrary()
3. Use the Document Monitor
Document Updates
public class UserService(IDocumentMonitor<User> monitor)
{
// Create a new document
public async Task<string> CreateUserAsync(User user)
{
return await monitor.Add(user);
}
// Get a document by ID
public async Task<User> GetUserAsync(string id)
{
return await monitor.Get(id);
}
// Update a document (only changed fields are sent)
public async Task UpdateUserAsync(User user)
{
user.Name = "New Name"; // Change is automatically tracked
user.Email = "new@email.com";
await monitor.SaveChanges(user);
}
// Lock a document for exclusive access
public async Task<IDisposable> LockUserAsync(User user)
{
return await monitor.LockDocument(user);
}
}
Query
MongoObject uses a custom Fluent Query API instead of LINQ for better performance, compile-time metadata support, and Native AOT compatibility.
var results = await monitor.Search()
.WithQuery(f =>
{
f.Name = "Case";
f.Age = f.Age.And(
f.Age.Lt(40000),
f.Age.Gt(5)
);
f.test(t =>
{
t.Name = "Andrew";
});
})
.WithMeta(meta =>
{
meta.LastModifiedAt = meta.LastModifiedAt.Lt(DateTime.UtcNow);
});
Compared with MongoDB.Driver
var collection = database.GetCollection<MongoDocument<User>>("Users");
var filter = Builders<MongoDocument<User>>.Filter.And(
// Document fields
Builders<MongoDocument<User>>.Filter.Eq(x => x.Document.Name, "Case"),
Builders<MongoDocument<User>>.Filter.And(
Builders<MongoDocument<User>>.Filter.Lt(x => x.Document.Age, 40000),
Builders<MongoDocument<User>>.Filter.Gt(x => x.Document.Age, 5)
),
// Nested MongoObject query
Builders<MongoDocument<User>>.Filter.Eq(x => x.Document.Test.Name, "Andrew"),
// Metadata field
Builders<MongoDocument<User>>.Filter.Lt(
x => x.Metadata["LastModifiedAt"].AsDateTime, DateTime.UtcNow
)
);
var results = await collection.Find(filter).ToListAsync();
Projections
Define projections directly on your properties with attributes:
[ProjectValue("Summary", ProjectionType.Include)]
public partial string Name { get; set; }
[ProjectValue("Summary", ProjectionType.Include)]
public partial int Age { get; set; }
MongoObject generates a strongly typed projection record at compile time:
var summary = await monitor.Search()
.WithQuery(f => f.Name = "Case")
.WithSummaryProjection();
Console.WriteLine(summary.First().Name); // strongly typed result
No ProjectionDefinition<T>, no field name strings, no manual serializer wiring.
4. Use the cli
The optional CLI keeps your MongoDB schema synchronized with your codebase by generating validation schemas, tracking renamed properties, and assisting with safe document migrations. (optional, By use of [MigrationSchema(OrphanFieldPolicy.AlwaysAsk)])
mo migrate build -p ../Path/To/Project
How It Works
Source Generation
When you decorate a class with [MongoObject], the source generator:
- Validates the class structure at compile time
- Generates partial property implementations with change tracking
- Creates metadata query and record types
- Generates type-safe search classes
Change Tracking
MongoObject uses INotifyPropertyChanged to track property changes:
var user = await monitor.Get(userId);
// user is now being tracked
user.Name = "Updated Name"; // Tracked: $set { "Document.Name": "Updated Name" }
user.Age = null; // Tracked: $unset ["Document.Age"]
// Only changed fields are sent to MongoDB
await monitor.SaveChanges(user);
Document Structure
Documents are wrapped in MongoDocument<T>:
public class MongoDocument<T>
{
public string Id { get; set; } // MongoDB _id
public T? Document { get; set; } // Your business data
public BsonDocument Metadata { get; set; } // Version, timestamps, etc.
}
Documentation
Full documentation is available at https://tenowg.github.io/MongoObject
Articles
- Getting Started
- Defining Documents
- Change Tracking
- Metadata
- Searching
- Projections
- Dependency Injection
Requirements
- .NET 10 SDK
- MongoDB 4.0+ (for change streams support)
- C# 14 (for partial properties)
MongoObject targets .NET 10 because it relies on C# 14 partial properties to generate strongly typed document implementations without runtime proxies or reflection.
Building from Source
# Debug build
dotnet build
# Release build (generates NuGet package)
dotnet build -c Release
# Run the demo project
dotnet run --project Progress
Roadmap
For the best idea of what is coming or what is on the Roadmap please look at current Issues.
Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
License
This project is licensed under the MIT License - see the LICENSE.txt file for details.
Acknowledgments
- Built with MongoDB.Driver
- Uses Roslyn Source Generators
- Versioning with MinVer
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- MongoDB.Driver (>= 3.8.0)
- SharpCompress (>= 0.48.0)
- Snappier (>= 1.3.1)
- System.Security.Cryptography.ProtectedData (>= 10.0.9)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Tenowg.MongoObjects:
| Package | Downloads |
|---|---|
|
Tenowg.MongoObjects.PropertyEncryption
Apply Encryption to MongoObject, a fluent codegenerated MongoDB ODM |
|
|
Tenowg.MongoObjects.MongoDistributedLock
Apply Distributed locking to MongoObject, a fluent codegenerated MongoDB ODM |
|
|
MongoObject.RedisDistributedLock
Package Description |
|
|
Tenowg.MongoObjects.RedisDistributedLock
Apply Redis as a MongoDistributedLock to MongoObjects, a fluent codegenerated MongoDB ODM |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.3.1-beta | 0 | 7/12/2026 |
| 0.3.0-beta | 67 | 7/6/2026 |
| 0.2.0-alpha | 82 | 6/10/2026 |
| 0.1.0-alpha | 62 | 6/5/2026 |