Migrate

首先安装以下工具 (工具不提供 ts 支持)

  1. npm install -g sequelize-cli
  1. mkdir models && cd models
  2. npm init -y
  3. npm i sequelize mysql2 -S

在安装了 sequelize 的 node 项目中运行以下,便可看到如下信息。

  1. $ sequelize
  2. Sequelize [Node: 8.1.2, CLI: 2.7.0, ORM: 4.2.0]
  3. Usage
  4. sequelize [task] [OPTIONS...]
  5. Available tasks
  6. db:migrate Run pending migrations.
  7. db:migrate:old_schema Update legacy migration table
  8. db:migrate:status List the status of all migrations
  9. db:migrate:undo Reverts a migration.
  10. db:migrate:undo:all Revert all migrations ran.
  11. db:seed Run specified seeder.
  12. db:seed:all Run every seeder.
  13. db:seed:undo Deletes data from the database.
  14. db:seed:undo:all Deletes data from the database.
  15. help Display this help text. Aliases: h
  16. init Initializes the project. [init:config, init:migrations, init:seeders, init:models]
  17. init:config Initializes the configuration.
  18. init:migrations Initializes the migrations.
  19. init:models Initializes the models.
  20. init:seeders Initializes the seeders.
  21. migration:create Generates a new migration file. Aliases: migration:generate
  22. model:create Generates a model and its migration. Aliases: model:generate
  23. seed:create Generates a new seed file. Aliases: seed:generate
  24. version Prints the version number. Aliases: v
  25. Available manuals
  26. help:db:migrate The documentation for "sequelize db:migrate".
  27. help:db:migrate:old_schema The documentation for "sequelize db:migrate:old_schema".
  28. help:db:migrate:status The documentation for "sequelize db:migrate:status".
  29. help:db:migrate:undo The documentation for "sequelize db:migrate:undo".
  30. help:db:migrate:undo:all The documentation for "sequelize db:migrate:undo:all".
  31. help:db:seed The documentation for "sequelize db:seed".
  32. help:db:seed:all The documentation for "sequelize db:seed:all".
  33. help:db:seed:undo The documentation for "sequelize db:seed:undo".
  34. help:db:seed:undo:all The documentation for "sequelize db:seed:undo:all".
  35. help:init The documentation for "sequelize init".
  36. help:init:config The documentation for "sequelize init:config".
  37. help:init:migrations The documentation for "sequelize init:migrations".
  38. help:init:models The documentation for "sequelize init:models".
  39. help:init:seeders The documentation for "sequelize init:seeders".
  40. help:migration:create The documentation for "sequelize migration:create".
  41. help:model:create The documentation for "sequelize model:create".
  42. help:seed:create The documentation for "sequelize seed:create".
  43. help:version The documentation for "sequelize version".

对于命令可以通过 help:xxxx 来查看帮助。

初始化

运行 sequelize init 进行初始化,该命令是以下命令的总和。

  1. init:config Initializes the configuration.
  2. init:migrations Initializes the migrations.
  3. init:models Initializes the models.
  4. init:seeders Initializes the seeders.

此时我们会得到几个文件夹 config / migrations / models/ seeders

config 是 sequelize 的配置目录,比如数据库地址等等,有好几个环境的配置项。migrations 是通过 js 文件里面定义好的创建数据表。修改数据库表的文件。models 就是我们自己定义模型的地方seeders 就是填充假数据的地方

查看如何创建一个模型

运行一下 sequelize help:model:create 命令,可以看到如下信息。

  1. $ sequelize help:model:create
  2. Sequelize [Node: 8.1.2, CLI: 2.7.0, ORM: 4.2.0]
  3. Loaded configuration file "config/config.json".
  4. Using environment "development".
  5. COMMANDS
  6. sequelize model:create -- Generates a model and its migration.
  7. sequelize model:generate -- Generates a model and its migration.
  8. DESCRIPTION
  9. This task generates a model file and its respective migration.
  10. It is necessary to specify the name of the new model as well as
  11. the model's attributes.
  12. The attributes can be specified as in the following (and semantically equal) examples:
  13. sequelize model:create --name User --attributes first_name:string,last_name:string,bio:text
  14. sequelize model:create --name User --attributes 'first_name:string last_name:string bio:text'
  15. sequelize model:create --name User --attributes 'first_name:string, last_name:string, bio:text'
  16. This command will generate a new migration and model definition:
  17. // the model file
  18. // located under models/user.js
  19. 'use strict';
  20. module.exports = function(sequelize, DataTypes) {
  21. var User = sequelize.define('User', {
  22. first_name: DataTypes.STRING,
  23. last_name: DataTypes.STRING,
  24. bio: DataTypes.TEXT
  25. }, {
  26. classMethods: {
  27. associate: function(models) {
  28. // associations can be defined here
  29. }
  30. }
  31. });
  32. return User;
  33. };
  34. // the migration file
  35. // located under migrations/20170628070436-create-user.js
  36. 'use strict';
  37. module.exports = {
  38. up: function(queryInterface, Sequelize) {
  39. return queryInterface.createTable('Users', {
  40. id: {
  41. allowNull: false,
  42. autoIncrement: true,
  43. primaryKey: true,
  44. type: Sequelize.INTEGER
  45. },
  46. first_name: {
  47. type: Sequelize.STRING
  48. },
  49. last_name: {
  50. type: Sequelize.STRING
  51. },
  52. bio: {
  53. type: Sequelize.TEXT
  54. },
  55. createdAt: {
  56. allowNull: false,
  57. type: Sequelize.DATE
  58. },
  59. updatedAt: {
  60. allowNull: false,
  61. type: Sequelize.DATE
  62. }
  63. });
  64. },
  65. down: function(queryInterface, Sequelize) {
  66. return queryInterface.dropTable('Users');
  67. }
  68. };

紧接着我们再运行一下

  1. sequelize model:create --name User --attributes first_name:string,last_name:string,bio:text
  2. sequelize model:create --name Book --attributes title:string,authorId:integer,desc:text

再来看看 models 文件夹和 migrations 文件夹就会发现出现了一些文件。

migrations/xxxxx-create-user.js 文件里面会看到,queryInterface.createTable很明显就是创建一个数据表而 queryInterface.dropTable就是删除一个数据表。

queryInterface 气死在 d.ts 文件里面可以找到,在 4206 - 4329 行,大家可以自己查找他能使用的方法。

定义一下关系

models/user.js

  1. classMethods: {
  2. associate: function(models) {
  3. // associations can be defined here
  4. models.User.hasMany(models.Book)
  5. models.Book.belongsTo(models.User);
  6. }
  7. }

解决无法关联的问题

接下来我们来测试一下方法

在项目根目录下面新建 index.js

  1. const db = require('./models');
  2. console.dir(db.sequelize.models.User)

运行一下,会发现 User 并没有与 Book 建立联系,这是什么情况呢?但是确实又是在对象里面看到了有classMethods 这个东西。

然后我们再来到 models/index.js 修改一下 27 行、

  1. Object.keys(db).forEach(function(modelName) {
  2. console.dir(db[modelName].options.classMethods.associate);
  3. console.log(db[modelName].associate);
  4. if (db[modelName].associate) {
  5. db[modelName].associate(db);
  6. }
  7. });

打印如下(index.js 是项目跟目录下面的)

  1. $ node index.js
  2. [Function: associate]
  3. undefined
  4. [Function: associate]
  5. undefined

这很明显,classMethods 上面的方法,没有代理到对象上面去。而且在之前也提到过 v4 版本好像不再支持 这种做法,所以,我们可以自己修改一下。

  1. Object.keys(db).forEach(function(modelName) {
  2. const associate = db[modelName].options.classMethods.associate;
  3. associate && associate(db);
  4. });

之后再次运行

  1. $ node index.js | grep Book
  2. models: { Book: [Object], User: [Circular] },
  3. { Books:
  4. as: 'Books',
  5. associationAccessor: 'Books',

很明显这一次就成功的进行了关联。

再次修改并,保存一下联系

  1. associate: function(models) {
  2. // associations can be defined here
  3. models.User.Book = models.User.hasOne(models.Book, {
  4. foreignKey: 'authorId'
  5. });
  6. models.Book.User = models.Book.belongsTo(models.User, {
  7. foreignKey: 'authorId'
  8. });
  9. }

seeder 填充

新建一个填充文件

  1. sequelize seed:create --name create_users

安装假数据生成工具

  1. npm i -D faker

假数据生成工具支持的配置请点这里

修改文件代码如下。

  1. 'use strict';
  2. const faker = require('faker');
  3. faker.locale = "zh_CN";
  4. const db = require('../models')
  5. module.exports = {
  6. up: function (queryInterface, Sequelize) {
  7. /*
  8. Add altering commands here.
  9. Return a promise to correctly handle asynchronicity.
  10. Example:
  11. return queryInterface.bulkInsert('Person', [{
  12. name: 'John Doe',
  13. isBetaMember: false
  14. }], {});
  15. */
  16. const Users = Array.from({length:20}, () => {
  17. return {
  18. first_name: faker.name.firstName(),
  19. last_name: faker.name.lastName(),
  20. bio: faker.name.jobTitle(),
  21. Book: {
  22. title: faker.lorem.word(),
  23. desc: faker.lorem.sentence()
  24. }
  25. }
  26. });
  27. const User = db.sequelize.models.User;
  28. return Promise.all(Users.map((item) => {
  29. return User.create(item, {
  30. include: [ User.Book ]
  31. });
  32. }))
  33. },
  34. down: function (queryInterface, Sequelize) {
  35. /*
  36. Add reverting commands here.
  37. Return a promise to correctly handle asynchronicity.
  38. Example:
  39. return queryInterface.bulkDelete('Person', null, {});
  40. */
  41. return queryInterface.bulkDelete('Person', null, {});
  42. }
  43. };

对于上面代码,觉得很难的自己用最简单的 queryInterface.bulkInsert 去插入数据就行了。嵌套的这种形式,我找了一下 API 发现只有 create 支持。

运行命令 sequelize db:migrate:status 查看当前 数据库表创建的情况

  1. down 20170628070615-create-user.js
  2. down 20170628070751-create-book.js

这里表示我们没有创建表。创建了之后会是 up 状态。

运行 sequelize db:migrate

  1. $ sequelize db:migrate
  2. Sequelize [Node: 8.1.2, CLI: 2.7.0, ORM: 4.2.0]
  3. Loaded configuration file "config/config.json".
  4. Using environment "development".
  5. == 20170628070615-create-user: migrating =======
  6. == 20170628070615-create-user: migrated (0.100s)
  7. == 20170628070751-create-book: migrating =======
  8. == 20170628070751-create-book: migrated (0.261s)
  9. =

此时数据库里面以及有了表了。而且多了一个表SequelizeMeta 这个是用来继续迁移的表。

  1. $ sequelize db:migrate:undo:all
  2. Sequelize [Node: 8.1.2, CLI: 2.7.0, ORM: 4.2.0]
  3. Loaded configuration file "config/config.json".
  4. Using environment "development".
  5. == 20170628070751-create-book: reverting =======
  6. == 20170628070751-create-book: reverted (0.017s)
  7. == 20170628070615-create-user: reverting =======
  8. == 20170628070615-create-user: reverted (0.008s)

sequelize db:migrate:undo:all 可以撤销刚刚所迁移的数据表,前提是你的 migarations 文件里面有写这个 down 方法。这种操作被称为回滚。undo:all 是撤销全部,而undo就是撤销一步。

  1. down: function(queryInterface, Sequelize) {
  2. return queryInterface.dropTable('Books');
  3. }

接下来继续运行命令

  1. sequelize db:migrate
  2. sequelize db:seed:all

便可在数据库里面看到数据,不过此操作也是可以回滚的,通过seed:undo:all即可。当然前提是你在代码里面以及定义了如何回滚。也就是down方法。