{"id":19106565,"url":"https://github.com/ffernandolima/mongo-db-data-access","last_synced_at":"2025-04-05T05:04:29.318Z","repository":{"id":43345897,"uuid":"438802905","full_name":"ffernandolima/mongo-db-data-access","owner":"ffernandolima","description":"It's a modern and generic data access structure for .NET and MongoDB. It supports UnitOfWork, Repository and QueryBuilder patterns. It also includes DbContext, IdGenerators and transactions support with replica set.","archived":false,"fork":false,"pushed_at":"2024-11-26T12:44:54.000Z","size":237,"stargazers_count":40,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-29T04:05:17.096Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ffernandolima.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-15T23:33:21.000Z","updated_at":"2025-02-20T19:16:21.000Z","dependencies_parsed_at":"2025-02-23T17:10:31.848Z","dependency_job_id":"77c1efe0-6d56-48cc-9272-ff27868a16b3","html_url":"https://github.com/ffernandolima/mongo-db-data-access","commit_stats":{"total_commits":23,"total_committers":1,"mean_commits":23.0,"dds":0.0,"last_synced_commit":"af539354981ae39ab9ca84587dc21108777bb706"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffernandolima%2Fmongo-db-data-access","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffernandolima%2Fmongo-db-data-access/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffernandolima%2Fmongo-db-data-access/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ffernandolima%2Fmongo-db-data-access/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ffernandolima","download_url":"https://codeload.github.com/ffernandolima/mongo-db-data-access/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289424,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T04:08:43.402Z","updated_at":"2025-04-05T05:04:29.293Z","avatar_url":"https://github.com/ffernandolima.png","language":"C#","funding_links":["https://www.buymeacoffee.com/fernandolima"],"categories":[],"sub_categories":[],"readme":"# MongoDB.DataAccess\n\nIt's a modern and generic data access structure for .NET and MongoDB. It supports UnitOfWork, Repository and QueryBuilder patterns. It also includes DbContext, IdGenerators and transactions support with replica set.\n\n## Give a Star! :star:\n\nIf you like or are using this project to learn or start your solution, please give it a star. Thanks!\n\n## Status\n\n[![build-and-publish Workflow Status](https://github.com/ffernandolima/mongo-db-data-access/actions/workflows/build-and-publish.yml/badge.svg?branch=main)](https://github.com/ffernandolima/mongo-db-data-access/actions/workflows/build-and-publish.yml/branch=main)\n\n | Package | NuGet |\n | ------- | ------- |\n | MongoDB.Data.Infrastructure.Abstractions | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.Infrastructure.Abstractions)](https://www.nuget.org/packages/MongoDB.Data.Infrastructure.Abstractions/1.8.1) |\n | MongoDB.Data.QueryBuilder.Abstractions | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.QueryBuilder.Abstractions)](https://www.nuget.org/packages/MongoDB.Data.QueryBuilder.Abstractions/1.8.1) |\n | MongoDB.Data.Repository.Abstractions | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.Repository.Abstractions)](https://www.nuget.org/packages/MongoDB.Data.Repository.Abstractions/1.8.1) |\n | MongoDB.Data.UnitOfWork.Abstractions | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.UnitOfWork.Abstractions)](https://www.nuget.org/packages/MongoDB.Data.UnitOfWork.Abstractions/1.8.1) |\n | ------- | ------- |\n | MongoDB.Data.Generators | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.Generators)](https://www.nuget.org/packages/MongoDB.Data.Generators/1.8.1) |\n | MongoDB.Data.Infrastructure | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.Infrastructure)](https://www.nuget.org/packages/MongoDB.Data.Infrastructure/1.8.1) |\n | MongoDB.Data.QueryBuilder | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.QueryBuilder)](https://www.nuget.org/packages/MongoDB.Data.QueryBuilder/1.8.1) |\n | MongoDB.Data.Repository | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.Repository)](https://www.nuget.org/packages/MongoDB.Data.Repository/1.8.1) |\n | MongoDB.Data.UnitOfWork | [![Nuget](https://img.shields.io/badge/nuget-v1.8.1-blue) ![Nuget](https://img.shields.io/nuget/dt/MongoDB.Data.UnitOfWork)](https://www.nuget.org/packages/MongoDB.Data.UnitOfWork/1.8.1) |\n\n## Installation\n\nMongoDB.DataAccess is available on Nuget.\n\n```\nInstall-Package MongoDB.Data.Infrastructure.Abstractions -Version 1.8.1\nInstall-Package MongoDB.Data.QueryBuilder.Abstractions -Version 1.8.1\nInstall-Package MongoDB.Data.Repository.Abstractions -Version 1.8.1\nInstall-Package MongoDB.Data.UnitOfWork.Abstractions -Version 1.8.1\n\nInstall-Package MongoDB.Data.Generators -Version 1.8.1\nInstall-Package MongoDB.Data.Infrastructure -Version 1.8.1\nInstall-Package MongoDB.Data.QueryBuilder -Version 1.8.1\nInstall-Package MongoDB.Data.Repository -Version 1.8.1\nInstall-Package MongoDB.Data.UnitOfWork -Version 1.8.1\n```\n\n**P.S.: MongoDB.Data.UnitOfWork depends on the other packages, so installing this package is enough.**\n\n## Usage\n\n#### The following code demonstrates basic usage of UnitOfWork, Repository and QueryBuilder patterns.\n\nFirst of all, please register the dependencies into the MS Built-In container:\n\n```C#\npublic class BloggingContext : MongoDbContext\n{\n    public BloggingContext(IMongoClient client, IMongoDatabase database, IMongoDbContextOptions options)\n        : base(client, database, options)\n    { }\n}\n\n// Register the DbContext\nservices.AddMongoDbContext\u003cIMongoDbContext, BloggingContext\u003e(\n    connectionString: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Blogging:ConnectionString\"),\n    databaseName: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Blogging:DatabaseName\"),\n    setupFluentConfigurationOptions: options =\u003e options.ScanningAssemblies = new[] { typeof(BloggingContext).Assembly });\n\n// Register the UnitOfWork\nservices.AddMongoDbUnitOfWork\u003cBloggingContext\u003e();\n```\n\nFor multiple databases:\n\n```C#\npublic class BloggingContext : MongoDbContext\n{\n    public BloggingContext(IMongoClient client, IMongoDatabase database, IMongoDbContextOptions options)\n        : base(client, database, options)\n    { }\n}\n\npublic class AccountingContext : MongoDbContext\n{\n    public AccountingContext(IMongoClient client, IMongoDatabase database, IMongoDbContextOptions options)\n        : base(client, database, options)\n    { }\n}\n\n// Register the DbContexts\nservices.AddMongoDbContext\u003cIMongoDbContext, BloggingContext\u003e(\n    connectionString: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Blogging:ConnectionString\"),\n    databaseName: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Blogging:DatabaseName\"),\n    setupFluentConfigurationOptions: options =\u003e options.ScanningAssemblies = new[] { typeof(BloggingContext).Assembly });\n\nservices.AddMongoDbContext\u003cIMongoDbContext, AccountingContext\u003e(\n    connectionString: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Accounting:ConnectionString\"),\n    databaseName: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Accounting:DatabaseName\"),\n    setupFluentConfigurationOptions: options =\u003e options.ScanningAssemblies = new[] { typeof(AccountingContext).Assembly });\n\n// Register the UnitOfWork\nservices.AddMongoDbUnitOfWork\u003cBloggingContext\u003e();\nservices.AddMongoDbUnitOfWork\u003cAccountingContext\u003e();\n```\n\nFor multi-tenancy:\n\nP.S: There are many approaches to implementing multi-tenancy in applications (Discriminator, Database per tenant, Schema per tenant...) and this one is just an example.\n\n```C#\npublic class BloggingContext : MongoDbContext\n{\n    public BloggingContext(IMongoClient client, IMongoDatabase database, IMongoDbContextOptions options)\n        : base(client, database, options)\n    { }\n}\n\n// Register the DbContexts\nservices.AddMongoDbContext\u003cIMongoDbContext, BloggingContext\u003e(\n    connectionString: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Blogging:TenantA:ConnectionString\"),\n    databaseName: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Blogging:TenantA:DatabaseName\"),\n    setupDbContextOptions: options =\u003e options.DbContextId = $\"{nameof(BloggingContext)} - TenantA\",\n    setupFluentConfigurationOptions: options =\u003e options.ScanningAssemblies = new[] { typeof(BloggingContext).Assembly });\n\nservices.AddMongoDbContext\u003cIMongoDbContext, BloggingContext\u003e(\n    connectionString: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Blogging:TenantB:ConnectionString\"),\n    databaseName: Configuration.GetValue\u003cstring\u003e(\"MongoSettings:Blogging:TenantB:DatabaseName\"),\n    setupDbContextOptions: options =\u003e options.DbContextId = $\"{nameof(BloggingContext)} - TenantB\",\n    setupFluentConfigurationOptions: options =\u003e options.ScanningAssemblies = new[] { typeof(BloggingContext).Assembly });\n\n// Register the UnitOfWork\nservices.AddMongoDbUnitOfWork\u003cBloggingContext\u003e();\n```\n\nAfter that, use the structure in your code like that:\n\n```C#\nprivate readonly IMongoDbUnitOfWork\u003cBloggingContext\u003e _unitOfWork;\n\n// Injection\npublic BlogsController(IMongoDbUnitOfWork\u003cBloggingContext\u003e unitOfWork)\n    =\u003e _unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork), $\"{nameof(unitOfWork)} cannot be null.\");\n\n// Or\n// Factory for multi-tenancy\npublic BlogsController(IMongoDbUnitOfWorkFactory\u003cBloggingContext\u003e unitOfWorkFactory, ITenantProvider tenantProvider) \n{\n    if (unitOfWorkFactory is null)\n    {\n        throw new ArgumentNullException(nameof(unitOfWorkFactory), $\"{nameof(unitOfWorkFactory)} cannot be null.\");\n    }\n\n    if (tenantProvider is null)\n    {\n        throw new ArgumentNullException(nameof(tenantProvider), $\"{nameof(tenantProvider)} cannot be null.\");\n    }\n\n    var tenantId = tenantProvider.GetTenantId();\n    _unitOfWork = unitOfWorkFactory.Create(tenantId);\n}\n\npublic void GetAllBlogs()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.MultipleResultQuery();\n\n    var blogs = repository.Search(query);\n}\n\npublic void GetAllBlogsProjection()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.MultipleResultQuery()\n                          .Select(selector =\u003e new \n                          {\n                              Name = selector.Title, \n                              Link = selector.Url, \n                              Type = selector.Type.Description \n                          });\n\n    var blogs = repository.Search(query);\n}\n\npublic void GetAllOrderedBlogs()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    IMongoDbQuery\u003cBlog\u003e query;\n    IList\u003cBlog\u003e blogs;\n\n    query = repository.MultipleResultQuery()\n                      .OrderByDescending(\"Id\");\n\n    blogs = repository.Search(query);\n\n    query = repository.MultipleResultQuery()\n                      .OrderByDescending(blog =\u003e blog.Id);\n\n    blogs = repository.Search(query);\n}\n\npublic void GetTopBlogs()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.MultipleResultQuery()\n                          .Top(10);\n\n    var blogs = repository.Search(query);\n}\n\npublic void GetPagedBlogs()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.MultipleResultQuery()\n                          .Page(1, 20);\n\n    var blogs = repository.Search(query);\n}\n\npublic void GetBlogsPagedList()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.MultipleResultQuery()\n                          .Page(1, 20);\n\n    var blogs = repository.Search(query)\n                          .ToPagedList(\n                            query.Paging.PageIndex,\n                            query.Paging.PageSize,\n                            query.Paging.TotalCount);\n}\n\npublic void GetFilteredBlogs()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.MultipleResultQuery()\n                          .AndFilter(blog =\u003e blog.Url.StartsWith(\"/a/\"))\n                          .AndFilter(blog =\u003e blog.Title.StartsWith(\"a\"))\n                          .AndFilter(blog =\u003e blog.Posts.Any());\n\n    var blogs = repository.Search(query);\n}\n\npublic void GetUrls()\n{\n    var repository = _unitOfWork.CustomRepository\u003cICustomBlogRepository\u003e();\n\n    var urls = repository.GetAllBlogUrls();\n}\n\npublic void GetBlogByUrl()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.SingleResultQuery()\n                          .AndFilter(blog =\u003e blog.Url.StartsWith(\"/a/\"))\n                          .OrderByDescending(blog =\u003e blog.Id);\n\n    var blogResult = repository.FirstOrDefault(query);\n}\n\npublic void GetBlogById()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.SingleResultQuery()\n                          .AndFilter(blog =\u003e blog.Id == 1);\n\n    var blogResult = repository.SingleOrDefault(query);\n}\n\npublic void GetBlogByIdProjection()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var query = repository.SingleResultQuery()\n                          .AndFilter(blog =\u003e blog.Id == 1)\n                          .Select(selector =\u003e new \n                          {\n                              selector.Id, \n                              Name = selector.Title, \n                              Link = selector.Url, \n                              Type = selector.Type.Description\n                          });\n\n    var blogResult = repository.SingleOrDefault(query);\n}\n\npublic void ExistsBlog()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var exists = repository.Any(blog =\u003e blog.Url.StartsWith(\"/a/\"));\n}\n\npublic void GetBlogCount()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var count = repository.Count();\n\n    var longCount = repository.LongCount();\n}\n\npublic void MaxBlogId()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var id = repository.Max(blog =\u003e blog.Id);\n}\n\npublic void MinBlogId()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    var id = repository.Min(blog =\u003e blog.Id);\n}\n\npublic void AddBlog()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    repository.InsertOne(Seeder.SeedBlog(51));\n\n    _unitOfWork.SaveChanges();\n}\n\npublic void UpdateBlog()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    repository.ReplaceOne(x =\u003e x.Id == id, model);\n\n    _unitOfWork.SaveChanges();\n}\n\npublic void DeleteBlog()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    repository.DeleteOne(x =\u003e x.Id == id);\n\n    _unitOfWork.SaveChanges();\n}\n\npublic void UpdateManyBlogs()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n\n    repository.UpdateMany(\n        blog =\u003e blogIds.Contains(blog.Id),\n        new Dictionary\u003cExpression\u003cFunc\u003cBlog, object\u003e\u003e, object\u003e\n        {\n            { blog =\u003e blog.Title, \"updated-title\" }\n        });\n    \n    _unitOfWork.SaveChanges();\n}\n\npublic void BulkWriteBlogs()\n{\n    var repository = _unitOfWork.Repository\u003cBlog\u003e();\n    \n    var requests = new List\u003cWriteModel\u003cBlog\u003e\u003e();\n\n    foreach (var blogId in blogIds)\n    {\n        var filter = Builders\u003cBlog\u003e.Filter.Eq(blog =\u003e blog.Id, blogId);\n        var definition = Builders\u003cBlog\u003e.Update.Set(blog =\u003e blog.Title, $\"a{blogId}-updated-title\");\n\n        requests.Add(new UpdateOneModel\u003cBlog\u003e(filter, definition));\n    }\n\n    repository.BulkWrite(requests);\n\n    _unitOfWork.SaveChanges();\n}\n```\n\nThe operations above are also available as async.\n\nPlease check some available samples [here](https://github.com/ffernandolima/mongo-db-data-access/tree/main/samples)\n\n## Support / Contributing\nIf you want to help with the project, feel free to open pull requests and submit issues. \n\n## Donate\n\nIf you would like to show your support for this project, then please feel free to buy me a coffee.\n\n\u003ca href=\"https://www.buymeacoffee.com/fernandolima\" target=\"_blank\"\u003e\u003cimg src=\"https://www.buymeacoffee.com/assets/img/custom_images/white_img.png\" alt=\"Buy Me A Coffee\" style=\"height: auto !important;width: auto !important;\" \u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fffernandolima%2Fmongo-db-data-access","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fffernandolima%2Fmongo-db-data-access","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fffernandolima%2Fmongo-db-data-access/lists"}