Sequelize.js: how to use migrations and sync
Solution 1:
Generating the "first migration"
In your case, the most reliable way is to do it almost manually. I would suggest to use sequelize-cli tool. The syntax is rather plain:
sequelize init
...
sequelize model:create --name User --attributes first_name:string,last_name:string,bio:text
This will create both model AND migration. Then, manually merge your existing models with generated with sequelize-cli, and do the same with migrations. After doing this, wipe database (if possible), and run
sequelize db:migrate
This will create schema will migrations. You should do this only once to switch to proper process of schema developments (without sync:force, but with authoritative migrations).
Later, when you need to change schema:
- Create a migration:
sequelize migration:create
- Write up and down functions in your migration file
- According to your changes in migration file, change your model manually
- Run
sequelize db:migrate
Running migrations on production
Obviously you can't ssh to production server and run migrations by hands. Use umzug, framework agnostic migration tool for Node.JS to perform pending migrations before app starts.
You can get a list of pending/not yet executed migrations like this:
umzug.pending().then(function (migrations) {
// "migrations" will be an Array with the names of
// pending migrations.
});
Then execute migrations (inside callback). The execute method is a general purpose function that runs for every specified migrations the respective function:
umzug.execute({
migrations: ['some-id', 'some-other-id'],
method: 'up'
}).then(function (migrations) {
// "migrations" will be an Array of all executed/reverted migrations.
});
And my suggestion is to do it before app starts and tries to serve routes every time. Something like this:
umzug.pending().then(function(migrations) {
// "migrations" will be an Array with the names of
// pending migrations.
umzug.execute({
migrations: migrations,
method: 'up'
}).then(function(migrations) {
// "migrations" will be an Array of all executed/reverted migrations.
// start the server
app.listen(3000);
// do your stuff
});
});
I can't try this right now, but at first look it should work.
UPD Apr. 2016
After a year, still useful, so sharing my current tips. For now, I'm installing sequelize-cli
package as required live dependancy, and then modify NPM startup scripts in package.json
like this:
...
"scripts": {
"dev": "grunt && sequelize db:migrate && sequelize db:seed:all && node bin/www",
"start": "sequelize db:migrate && sequelize db:seed:all && node bin/www"
},
...
The only thing I need to do on production server is npm start
. This command will run all migrations, apply all seeders and start app server. No need to call umzug manually.
Solution 2:
Just learning this myself, but I think I would recommend using migrations now so you get used to them. I've found the best thing for figuring out what goes in the migration is to look at the sql on the tables created by sequelize.sync()
and then build the migrations from there.
migrations -c [migration name]
Will create the template migration file in a migrations directory. You can then populate it with the fields you need created. This file will need to include createdAt
/updatedAt
, fields needed for associations, etc.
For initial table creation down should have:
migration.dropTable('MyTable');
But subsequent updates to the table structure can leave this out and just use alter table.
./node_modules/.bin/sequelize --migrate
An example create would look like:
module.exports = {
up: function(migration, DataTypes, done) {
migration.createTable(
'MyTable',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
bigString: {type: DataTypes.TEXT, allowNull: false},
MyOtherTableId: DataTypes.INTEGER,
createdAt: {
type: DataTypes.DATE
},
updatedAt: {
type: DataTypes.DATE
}
});
done();
},
down: function(migration, DataTypes, done) {
migration.dropTable('MyTable');
done();
}
To redo from start:
./node_modules/.bin/sequelize --migrate --undo
./node_modules/.bin/sequelize --migrate
I'm using coffee to run a seed file to populate the tables after:
coffee server/seed.coffee
This just has a create function in it that looks something like:
user = db.User.create
username: 'bob'
password: 'suruncle'
email: '[email protected]'
.success (user) ->
console.log 'added user'
user_id = user.id
myTable = [
field1: 'womp'
field2: 'rat'
subModel: [
field1: 'womp'
,
field1: 'rat'
]
]
Remember to take your sync()
out of index in your models or it will overwrite what the migrations and seed do.
Docs are at http://sequelize.readthedocs.org/en/latest/docs/migrations/ of course. But the basic answer is you have to add everything in yourself to specify the fields you need. It doesn't do it for you.