Module wither::migration
[−]
[src]
Interface for schema migrations.
As your system evolves over time, you may find yourself needing to evolve the data in your
databases along with your models. An IntervalMigration
is a great place to start & should be defined in your Model
implementation.
// snip ... // Define any migrations which your model needs in this method. // You should never have to remove these from your source code. fn migrations() -> Vec<Box<wither::Migration>> { return vec![ Box::new(wither::IntervalMigration{ name: String::from("remove-oldfield"), // NOTE: use a logical time here. A day after your deployment date, or the like. threshold: chrono::Utc.ymd(2100, 1, 1).and_hms(1, 0, 0), filter: doc!{"oldfield": doc!{"$exists": true}}, set: None, unset: Some(doc!{"oldfield": ""}), }), ]; } // snip ...
Remember, MongoDB is not a SQL based system. There is no true database level schema
enforcement. IntervalMigration
s bridge this gap quite nicely.
Model
s defined in this system use serde, and as such, it is quite
likely that no explicit schema migration is needed for changes to your model. Often times,
field defaults can be used and no additional
overhead would be required.
With that said, schema migrations in this system:
- are defined in Rust code. Allowing them to live as child elements of your data models.
- are executed per model, whenever
Model::sync
is called — which should be once per system life cycle, early on at boottime. When dealing with an API service, this should occur before the API begins handling traffic. - require no downtime to perform.
- require minimal configuration. The logic you use directly in your model for connecting to the backend is used for the migrations system as well.
- require no imperative logic. Simply declare your
filter
,$set
&$unset
documents, and the rest will be taken care of.
An important question which you should be asking at this point is "Well, how is this going to work at scale?". This is an excellent question, of course. The answer is that it depends on how you write your migrations. Here are a few pointers & a few notes to help you succeed.
- be sure that the queries used by your migrations are covered. Just add some new indexes to
your
Model::indexes
implementation to be sure. Indexes will always be synced byModel::sync
before migrations are executed for this reason. - when you are dealing with massive amounts of data, and every document needs to be touched,
indexing still matters! Especially when using an
IntervalMigration
, as you may be under heavy write load, and new documents will potentially be introduced having the old schema after the first service performs the migration. Schema convergence will only take place after all service instances have been updated & have executed their migrations.
Currently, the following migration types are available. If there is a new migration "type" which you find yourself in need of, please open an issue!
Structs
IntervalMigration |
A migration type which allows execution until the specifed |
Traits
Migration |
A trait definition for objects which can be used to manage schema migrations. |