{"id":23819780,"url":"https://github.com/sroddis/mongo.migration","last_synced_at":"2025-10-06T22:04:20.701Z","repository":{"id":46831974,"uuid":"96630981","full_name":"SRoddis/Mongo.Migration","owner":"SRoddis","description":"On-the-fly migrations with MongoDB C# Driver","archived":false,"fork":false,"pushed_at":"2024-08-05T17:41:52.000Z","size":479,"stargazers_count":178,"open_issues_count":36,"forks_count":63,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-03-28T20:11:09.517Z","etag":null,"topics":["csharp","dotnet","migration","migrations","mongodb","mongodb-driver","schema","schema-migrations"],"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/SRoddis.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-08T16:35:12.000Z","updated_at":"2025-03-05T21:49:08.000Z","dependencies_parsed_at":"2024-01-02T22:44:48.753Z","dependency_job_id":"6429f5f6-5f5d-4dc7-b6b3-0a3a5383ca99","html_url":"https://github.com/SRoddis/Mongo.Migration","commit_stats":{"total_commits":252,"total_committers":18,"mean_commits":14.0,"dds":0.3293650793650794,"last_synced_commit":"8016d4323bd7e8655ac1bf51dc46f8528cc59db8"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SRoddis%2FMongo.Migration","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SRoddis%2FMongo.Migration/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SRoddis%2FMongo.Migration/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SRoddis%2FMongo.Migration/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SRoddis","download_url":"https://codeload.github.com/SRoddis/Mongo.Migration/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247249537,"owners_count":20908212,"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":["csharp","dotnet","migration","migrations","mongodb","mongodb-driver","schema","schema-migrations"],"created_at":"2025-01-02T07:15:12.263Z","updated_at":"2025-10-06T22:04:15.644Z","avatar_url":"https://github.com/SRoddis.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![.NET](https://github.com/SRoddis/Mongo.Migration/actions/workflows/dotnet.yml/badge.svg)](https://github.com/SRoddis/Mongo.Migration/actions/workflows/dotnet.yml)\n[![Coverage Status](https://coveralls.io/repos/github/SRoddis/Mongo.Migration/badge.svg)](https://coveralls.io/github/SRoddis/Mongo.Migration)\n[![NuGet](https://img.shields.io/nuget/dt/Mongo.Migration.svg)](https://www.nuget.org/packages/Mongo.Migration/)\n[![NuGet](https://img.shields.io/nuget/v/Mongo.Migration.svg)](https://www.nuget.org/packages/Mongo.Migration/)\n![GitHub last commit](https://img.shields.io/github/last-commit/sroddis/Mongo.Migration.svg)\n\n# Mongo.Migration\n\n\n![](https://media.giphy.com/media/10tLOFXDFDjgQM/giphy.gif)\n\n\nMongo.Migration is designed for the [MongoDB C# Driver](https://github.com/mongodb/mongo-csharp-driver) to migrate your documents easily and on-the-fly.\nNo more downtime for schema-migrations. Just write small and simple `migrations`.\n\n`**Edit**`\n\nWith version 3.0.0 of Mongo.Migration I added the possibility to run migrations on StartUp. In order to keep the core of Mongo.Migration in focus, it is still possible to run migrations at runtime (on-the-fly). In addition, there is now the option of executing migrations at the start of the application.\n\n`**PLEASE NOTE**` If you use on-the-fly migration updates, aggregation pipeline and projections are not handled, because they don’t use serialization. You have to handle them yourself.\n\nWith version 4.0.0 of Mongo.Migration was added the possibility to run database migrations on StartUp. \nNow exist additional option of executing migrations which can manipulate the mongo database insert documents, rename collections and other operations that you need. It's more generic operations than only manipulate document when exists.\n\n# Installation\n\nInstall via nuget https://www.nuget.org/packages/Mongo.Migration\n\n```\nPM\u003e Install-Package Mongo.Migration\n```\n\n# Document migrations quick Start \n\n#### .Net Framework\n1. Initialize `MongoMigration` behind the `MongoClient`. ([Mongo2Go](https://github.com/Mongo2Go/Mongo2Go))\n\n```csharp\n// Init MongoDB\nvar runner = MongoDbRunner.Start(); // Mongo2Go\nvar client = new MongoClient(runner.ConnectionString);\n\n// Init MongoMigration\nMongoMigrationClient.Initialize(client);\n```\n    \n#### .Net Core\n\n1.1 Add `MongoMigration` with the StartupFilter (`IMongoClient` has to be registered at the DI-container before)\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddMvc();\n\n    _client = new MongoClient( _configuration.GetSection(\"MongoDb:ConnectionString\").Value);\n    \n    services.AddSingleton\u003cIMongoClient\u003e(_client);\n                \n    services.AddMigration();\n}\n```\n1.2 Add `MongoMigration` with the StartupFilter add connection setting to use separate client\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddMvc();\n\n    _client = new MongoClient( _configuration.GetSection(\"MongoDb:ConnectionString\").Value);\n    \n    services.AddSingleton\u003cIMongoClient\u003e(_client);\n                \n    services.AddMigration(new MongoMigrationSettings\n    {\n        ConnectionString = _configuration.GetSection(\"MongoDb:ConnectionString\").Value,\n        Database = _configuration.GetSection(\"MongoDb:Database\").Value, \n        VersionFieldName = \"TestVersionName\" // Optional\n    });\n}\n```\n\n    \n2. Implement `IDocument` or add `Document` to your entities to provide the `DocumentVersion`. (Optional) Add the `RuntimeVersion` attribute to mark the current version of the document. So you have the possibility to downgrade in case of a rollback.\n\n```csharp\n[RuntimeVersion(\"0.0.1\")]\npublic class Car : IDocument\n{\n    public ObjectId Id { get; set; }\n\n    public string Type { get; set; }\n\n    public int Doors { get; set; }\n\n    public DocumentVersion Version { get; set; }\n}\n```\n3. Create a migration by extending the abstract class `DocumentMigration\u003cTDocument\u003e`. Best practice for the version is to use [Semantic Versioning](http://semver.org/) but ultimately it is up to you. You could simply use the patch version to count the number of migrations. If there is a duplicate for a specific type an exception is thrown on initialization.\n\n```csharp\npublic class M001_RenameDorsToDoors : DocumentMigration\u003cCar\u003e\n{\n    public M001_RenameDorsToDoors()\n        : base(\"0.0.1\")\n    {\n    }\n\n    public override void Up(BsonDocument document)\n    {\n        var doors = document[\"Dors\"].ToInt32();\n        document.Add(\"Doors\", doors);\n        document.Remove(\"Dors\");\n    }\n\n    public override void Down(BsonDocument document)\n    {\n        var doors = document[\"Doors\"].ToInt32();\n        document.Add(\"Dors\", doors);\n        document.Remove(\"Doors\");\n    }\n}\n```\n4. `(Optional)` If you choose to put your migrations into an extra project, \nadd the suffix `\".MongoMigrations\"` to the name and make sure it is referenced in the main project. By convention Mongo.Migration collects all .dlls named like that in your bin folder.\n    \nCompile, run and enjoy!\n\n## How to use document migration\n\nWith version 3.0.0 of Mongo.Migration I added the possibility to run migrations on StartUp. \nIn order to keep the core of Mongo.Migration in focus, it is still possible to run migrations at runtime (on-the-fly). \nIn addition, there is now the option of executing migrations at the start of the application.\n\n#### Document migration at runtime\n\nSee `Quick Start ` \n\n#### Document migration on startup\n\nIf you want to run migrations on StartUp, the only thing you have to do is add the attribute `CollectionLocation`. \nNow all migrations you add for a `IDocument` will be executed at StartUp.\n\n```csharp\n    [CollectionLocation(\"Car\", \"TestCars\")]\n    public class Car : IDocument\n    {\n        public ObjectId Id { get; set; }\n\n        public string Type { get; set; }\n\n        public int Doors { get; set; }\n\n        public DocumentVersion Version { get; set; }\n    }\n```\n\nAdditionally you can fix the version of the document with  `StartUpVersion`\n\n```csharp\n    [StartUpVersion(\"0.1.1\")]\n    [CollectionLocation(\"Car\", \"TestCars\")]\n    public class Car : IDocument\n    {\n        public ObjectId Id { get; set; }\n\n        public string Type { get; set; }\n\n        public int Doors { get; set; }\n\n        public DocumentVersion Version { get; set; }\n    }\n```\n\n`**PLEASE NOTE**` \nMongo.Migration uses the IStartUpFilter for .net core. \nMaybe you want to read this [article](https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-part-1/), to check if there is a better option to migrate with Mongo.Migration at StartUp.\n\n#### Document migration on startup and at runtime\n\nThis is an example how you can use both.\nAt startup the version will be 0.0.1 and at runtime, when a document will be deserialized the version will be migrated to 0.1.1\n\n```csharp\n    [RuntimeVersion(\"0.1.1\")]\n    [StartUpVersion(\"0.0.1\")]\n    [CollectionLocation(\"Car\", \"TestCars\")]\n    public class Car : IDocument\n    {\n        public ObjectId Id { get; set; }\n\n        public string Type { get; set; }\n\n        public int Doors { get; set; }\n\n        public DocumentVersion Version { get; set; }\n    }\n```\n\n\n### Annotations\n\n#### RuntimeVersion\nAdd `RuntimeVersion` attribute to mark the current version of the document. So you have the possibility to downgrade in case of a rollback.\nIf you do not set the `RuntimeVersion`, all migrations will be applied.\n\n```csharp\n[RuntimeVersion(\"0.0.1\")]   \npublic class Car : IDocument\n...\n```\n#### CollectionLocation\nAdd `CollectionLocation` attribute if you want to migrate your collections at startup. This attribute tells Mongo.Migration where to find your Collections.\n\n```csharp\n[CollectionLocation(\"Car\", \"TestCars\")]\npublic class Car : IDocument\n...   \n```\n#### StartUpVersion\nAdd `StartUpVersion` attribute to set the version you want to migrate to at startup. This attribute limits the migrations to be performed on startup\n\n```csharp\n[StartUpVersion(\"0.0.1\")]\npublic class Car : IDocument\n...\n```\n\n# Database migrations quick start\n\n#### .Net Framework\n1. Initialize `MongoMigration` behind the `MongoClient`. ([Mongo2Go](https://github.com/Mongo2Go/Mongo2Go))\n\n```csharp\n// Init MongoDB\nvar runner = MongoDbRunner.Start(); // Mongo2Go\nvar client = new MongoClient(runner.ConnectionString);\n\n// Init MongoMigration\n MongoMigrationClient.Initialize(\n                client,\n                new MongoMigrationSettings()\n                {\n                    ConnectionString = runner.ConnectionString,\n                    Database = \"TestCars\"\n                },\n                new LightInjectAdapter(new LightInject.ServiceContainer()))\n```\n    \n#### .Net Core\n\n1.1 Add `MongoMigration` with the StartupFilter (`IMongoClient` has to be registered at the DI-container before)\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddMvc();\n\n    _client = new MongoClient( _configuration.GetSection(\"MongoDb:ConnectionString\").Value);\n    \n    services.AddSingleton\u003cIMongoClient\u003e(_client);\n                \n    services.AddMigration(new MongoMigrationSettings()\n                         {\n                             ConnectionString = runner.ConnectionString,\n                             Database = \"TestCars\"\n                         });\n}\n\n```\n1.2 Add `MongoMigration` with the StartupFilter add connection setting to use separate client\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddMvc();\n                \n    services.AddMigration(new MongoMigrationSettings\n    {\n        ConnectionString = _configuration.GetSection(\"MongoDb:ConnectionString\").Value,\n        Database = _configuration.GetSection(\"MongoDb:Database\").Value, \n        DatabaseMigrationVersion = new DocumentVersion(2,0,0) // Optional\n    });\n}\n```\n\n    \n2. Create a migration by extending the abstract class `DatabaseMigration`. Best practice for the version is to use [Semantic Versioning](http://semver.org/) but ultimately it is up to you. You could simply use the patch version to count the number of migrations. All database migrations you add for a database will be executed at StartUp.\n\n```csharp\n    public class M100_AddNewCar : DatabaseMigration\n    {\n        public M100_AddNewCar()\n            : base(\"1.0.0\")\n        {\n        }\n\n        public override void Up(IMongoDatabase db)\n        {\n            var collection = db.GetCollection\u003cCar\u003e(\"Car\");\n            collection.InsertOne(new Car\n            {\n                Doors = 123,\n                Type = \"AddedInMigration\"\n            });\n        }\n\n        public override void Down(IMongoDatabase db)\n        {\n            var collection = db.GetCollection\u003cCar\u003e(\"Car\");\n            collection.DeleteOne(Builders\u003cCar\u003e.Filter.Eq(c =\u003e c.Type, \"AddedInMigration\"));\n        }\n    }\n```\n\n### Annotations\n#### CollectionLocation\n`CollectionLocation` attribute if you not specify database in MongoMigrationSettings then database from attribure will be use at startup.\n\n#### Setup current database version\nDatabase will downgrade to current version using database migrations\n```csharp\nnew MongoMigrationSettings()\n{\n    ...\n    DatabaseMigrationVersion = new DocumentVersion(2,0,0)\n}\n``` \n\n## Dependency injection\nWith the latest update (3.0.94) I added a requested feature to `Mongo.Migration`. `Migration` can be injected with dependencies from now on.\n\n#### .NetCore\nIt is pitty simple with .NetCore. `Mongo.Migration` uses the `IServiceProvider` to resolve all used dependencies. So you have access to all registered dependencies.\n\n\n#### .Net Framework\nWhen you initialize `Mongo.Migration` you can now add a `IContainerAdapter`. At the moment following Containers can be used out of the box:\n- LightInject\n- .NetCore ServiceProvider\n- ... more planned in the future.\n\nIf you use an other Container, you have to implement the interface yourself. As an example, see `LightInjectAdapter`.\n\nWhen that is done, you can pass the Adapter as a parameter to initialize `Mongo.Migration`.\n\n```csharp\n    // Your Container\n    var conatiner = ServiceContainer()\n    ontainer.Register\u003cIYourDependency, YourDependency\u003e();\n\n    // Init MongoDB\n    var runner = MongoDbRunner.Start(); // Mongo2Go\n    var client = new MongoClient(runner.ConnectionString);\n\n    // Your Adapter implementation to abstract the container\n    var adapter = new LightInjectAdapter(container)\n\n    // Init MongoMigration\n    MongoMigrationClient.Initialize(client, adapter);\n```\n\n```csharp\n    public class M001_RenameDorsToDoors : DocumentMigration\u003cCar\u003e\n    {\n        private readonly IYourDependency _service;\n\n        public M001_RenameDorsToDoors(IYourDependency service)\n            : base(\"0.0.1\")\n        {\n            _service = service;\n        }\n\n    ...\n```\n\n## Document migrations demo\n\nInside of the repository you can find a [Mongo.Migration.Demo]( https://github.com/SRoddis/Mongo.Migration/tree/master/Mongo.Migration.Demo) which is a simple demo to show how to use Mongo.Migration. \n\n1. Compile and run the demo application.\n2. Now you should see the following output in the console.\n\n```bash\n\tMigrate from:\n\t{ \"_id\" : ObjectId(\"59624d5beb5bb330386cd859\"), \"Dors\" : 3, \"Type\" : \"Cabrio\", \"UnnecessaryField\" : \"\" }\n\n\t{ \"_id\" : ObjectId(\"59624d5beb5bb330386cd85a\"), \"Dors\" : 5, \"Type\" : \"Combi\", \"UnnecessaryField\" : \"\" }\n\n\t{ \"_id\" : ObjectId(\"59624d5beb5bb330386cd85b\"), \"Doors\" : 3, \"Type\" : \"Truck\", \"UnnecessaryField\" : \"\", \"Version\" : \"0.0.1\" }\n\n\t{ \"_id\" : ObjectId(\"59624d5beb5bb330386cd85c\"), \"Doors\" : 5, \"Type\" : \"Van\", \"Version\" : \"0.1.1\" }\n\n\tTo:\n\t{ \"_id\" : ObjectId(\"59624d5beb5bb330386cd859\"), \"Type\" : \"Cabrio\", \"Doors\" : 3, \"Version\" : \"0.1.1\" }\n\n\t{ \"_id\" : ObjectId(\"59624d5beb5bb330386cd85a\"), \"Type\" : \"Combi\", \"Doors\" : 5, \"Version\" : \"0.1.1\" }\n\n\t{ \"_id\" : ObjectId(\"59624d5beb5bb330386cd85b\"), \"Type\" : \"Truck\", \"Doors\" : 3, \"Version\" : \"0.1.1\" }\n\n\t{ \"_id\" : ObjectId(\"59624d5beb5bb330386cd85c\"), \"Type\" : \"Van\", \"Doors\" : 5, \"Version\" : \"0.1.1\" }\n\n\tNew Car was created with version: 0.1.1\n\n\tPress any Key to exit...\n```\n\n3. `(Optional)` Run [Mongo.Migration.Demo.Performance.Console]( https://github.com/SRoddis/Mongo.Migration/tree/master/Mongo.Migration.Demo.Performance.Console)\n\n\n## Database migrations demo\n\nInside of the repository you can find a [Mongo.Migration.Database.Demo]( https://github.com/SRoddis/Mongo.Migration/tree/master/Mongo.Migration.Database.Demo) which is a simple demo to show how to use database Mongo.Migration. \n\n1. Compile and run the demo application.\n2. Now you should see the following output in the console.\n\n```bash\nApply database migrations:\n\n\n{ \"_id\" : ObjectId(\"5ead80b68f9c4c402c35ebb9\"), \"MigrationId\" : \"Mongo.Migration.Database.Demo.Migrations.M100_AddNewCar\", \"Version\" : \"1.0.0\" }\n\n{ \"_id\" : ObjectId(\"5ead80b68f9c4c402c35ebba\"), \"MigrationId\" : \"Mongo.Migration.Database.Demo.Migrations.M200_UpdateNewCar\", \"Version\" : \"2.0.0\" }\n\n{ \"_id\" : ObjectId(\"5ead80b78f9c4c402c35ebbb\"), \"MigrationId\" : \"Mongo.Migration.Database.Demo.Migrations.M300_AddSparePartsCollection\", \"Version\" : \"3.0.0\" }\n\nNew Car was added and updated in database migrations:\n{ \"_id\" : ObjectId(\"5ead80b68f9c4c402c35ebb8\"), \"Type\" : \"AddedInMigration\", \"Doors\" : 222 }\n\nNew collection was added in database:\nSparePart\n\n\n\nPress any Key to exit...\n```\n\n\n## Suggestions\n\nDeploy the migrations in a separate artifact. Otherwise you lose the ability to downgrade in case of a rollback.\n\n## Performance\n\nThe performance is measured on every push to the repository with a small performance-test. It measures the time MongoDB needs to insert and read `n documents` (5000) with and without Mongo.Migration. The difference is asserted and should be not higher than a given tolerance (150ms).\n\nExample output of the automated test:\n```bash\nMongoDB: 73ms, Mongo.Migration: 168ms, Diff: 95ms (Tolerance: 150ms), Documents: 5000, Migrations per Document: 2\n\nMongoDB: 88ms, Mongo.Migration: 109ms, Diff: 21ms (Tolerance: 70ms), Documents: 1500, Migrations per Document: 2\n\nMongoDB: 62ms, Mongo.Migration: 63ms, Diff: 1ms (Tolerance: 40ms), Documents: 100, Migrations per Document: 2\n\nMongoDB: 48ms, Mongo.Migration: 50ms, Diff: 2ms (Tolerance: 10ms), Documents: 10, Migrations per Document: 2\n\n```\n\nAfter bigger changes the code is analyzed with profiling tools to check for performance or memory problems.\n\n## Next Feature/Todo\n\n\t1. Intercept updates, aggregation pipeline and projections.\n\n## Copyright\n\nCopyright © 2018 Sean Roddis\n\n## License\n\nMongo.Migration is licensed under [MIT](http://www.opensource.org/licenses/mit-license.php \"Read more about the MIT license form\"). Refer to license.txt for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsroddis%2Fmongo.migration","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsroddis%2Fmongo.migration","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsroddis%2Fmongo.migration/lists"}