Model definition - 模型定义

要定义模型和表之间的映射,请使用define方法。 随后Sequelize将自动添加createdAtupdatedAt属性。 因此,您将能够知道数据库条目何时进入数据库以及最后一次更新时。 如果您不想在模型上使用时间戳,只需要一些时间戳,或者您正在使用现有的数据库,其中列被命名为别的东西,直接跳转到configuration以查看如何执行此操作。

  1. const Project = sequelize.define('project', {
  2. title: Sequelize.STRING,
  3. description: Sequelize.TEXT
  4. })
  5. const Task = sequelize.define('task', {
  6. title: Sequelize.STRING,
  7. description: Sequelize.TEXT,
  8. deadline: Sequelize.DATE
  9. })

你还可以在每列上进行一些设置:

  1. const Foo = sequelize.define('foo', {
  2. // 如果未赋值,则自动设置值为 TRUE
  3. flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true},
  4. // 设置默认时间为当前时间
  5. myDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },
  6. // 将allowNull设置为false会将NOT NULL添加到列中,
  7. // 这意味着当列为空时执行查询时将从DB抛出错误。
  8. // 如果要在查询DB之前检查值不为空,请查看下面的验证部分。
  9. title: { type: Sequelize.STRING, allowNull: false},
  10. // 创建具有相同值的两个对象将抛出一个错误。 唯一属性可以是布尔值或字符串。
  11. // 如果为多个列提供相同的字符串,则它们将形成复合唯一键。
  12. uniqueOne: { type: Sequelize.STRING, unique: 'compositeIndex'},
  13. uniqueTwo: { type: Sequelize.INTEGER, unique: 'compositeIndex'},
  14. // unique属性用来创建一个唯一约束。
  15. someUnique: {type: Sequelize.STRING, unique: true},
  16. // 这与在模型选项中创建索引完全相同。
  17. {someUnique: {type: Sequelize.STRING}},
  18. {indexes: [{unique: true, fields: ['someUnique']}]},
  19. // primaryKey用于定义主键。
  20. identifier: { type: Sequelize.STRING, primaryKey: true},
  21. // autoIncrement可用于创建自增的整数列
  22. incrementMe: { type: Sequelize.INTEGER, autoIncrement: true },
  23. // 你可以通过'field'属性指定自定义字段名称:
  24. fieldWithUnderscores: { type: Sequelize.STRING, field: 'field_with_underscores' },
  25. // 这可以创建一个外键:
  26. bar_id: {
  27. type: Sequelize.INTEGER,
  28. references: {
  29. // 这是引用另一个模型
  30. model: Bar,
  31. // 这是引用模型的列名称
  32. key: 'id',
  33. // 这声明什么时候检查外键约束。 仅限PostgreSQL。
  34. deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
  35. }
  36. }
  37. })

注释选项也可以在表上使用, 查看 model configuration

时间戳

默认情况下,Sequelize 会将 createdAtupdatedAt 属性添加到模型中,以便您能够知道数据库条目何时进入数据库以及何时被更新。

请注意,如果您使用 Sequelize 迁移,则需要将 createdAtupdatedAt 字段添加到迁移定义中:

  1. module.exports = {
  2. up(queryInterface, Sequelize) {
  3. return queryInterface.createTable('my-table', {
  4. id: {
  5. type: Sequelize.INTEGER,
  6. primaryKey: true,
  7. autoIncrement: true,
  8. },
  9. // 时间戳
  10. createdAt: Sequelize.DATE,
  11. updatedAt: Sequelize.DATE,
  12. })
  13. },
  14. down(queryInterface, Sequelize) {
  15. return queryInterface.dropTable('my-table');
  16. },
  17. }

如果您不想在模型上使用时间戳,只需要一些时间戳记,或者您正在使用现有的数据库,其中列被命名为别的东西,直接跳转到 configuration 以查看如何执行此操作。

数据类型

以下是 Sequelize 支持的一些数据类型。 有关完整和更新的列表, 参阅 DataTypes.

  1. Sequelize.STRING // VARCHAR(255)
  2. Sequelize.STRING(1234) // VARCHAR(1234)
  3. Sequelize.STRING.BINARY // VARCHAR BINARY
  4. Sequelize.TEXT // TEXT
  5. Sequelize.TEXT('tiny') // TINYTEXT
  6. Sequelize.INTEGER // INTEGER
  7. Sequelize.BIGINT // BIGINT
  8. Sequelize.BIGINT(11) // BIGINT(11)
  9. Sequelize.FLOAT // FLOAT
  10. Sequelize.FLOAT(11) // FLOAT(11)
  11. Sequelize.FLOAT(11, 12) // FLOAT(11,12)
  12. Sequelize.REAL // REAL PostgreSQL only.
  13. Sequelize.REAL(11) // REAL(11) PostgreSQL only.
  14. Sequelize.REAL(11, 12) // REAL(11,12) PostgreSQL only.
  15. Sequelize.DOUBLE // DOUBLE
  16. Sequelize.DOUBLE(11) // DOUBLE(11)
  17. Sequelize.DOUBLE(11, 12) // DOUBLE(11,12)
  18. Sequelize.DECIMAL // DECIMAL
  19. Sequelize.DECIMAL(10, 2) // DECIMAL(10,2)
  20. Sequelize.DATE // DATETIME for mysql / sqlite, TIMESTAMP WITH TIME ZONE for postgres
  21. Sequelize.DATE(6) // DATETIME(6) for mysql 5.6.4+. Fractional seconds support with up to 6 digits of precision
  22. Sequelize.DATEONLY // DATE without time.
  23. Sequelize.BOOLEAN // TINYINT(1)
  24. Sequelize.ENUM('value 1', 'value 2') // An ENUM with allowed values 'value 1' and 'value 2'
  25. Sequelize.ARRAY(Sequelize.TEXT) // Defines an array. PostgreSQL only.
  26. Sequelize.ARRAY(Sequelize.ENUM) // Defines an array of ENUM. PostgreSQL only.
  27. Sequelize.JSON // JSON column. PostgreSQL, SQLite and MySQL only.
  28. Sequelize.JSONB // JSONB column. PostgreSQL only.
  29. Sequelize.BLOB // BLOB (bytea for PostgreSQL)
  30. Sequelize.BLOB('tiny') // TINYBLOB (bytea for PostgreSQL. Other options are medium and long)
  31. Sequelize.UUID // UUID datatype for PostgreSQL and SQLite, CHAR(36) BINARY for MySQL (use defaultValue: Sequelize.UUIDV1 or Sequelize.UUIDV4 to make sequelize generate the ids automatically)
  32. Sequelize.RANGE(Sequelize.INTEGER) // Defines int4range range. PostgreSQL only.
  33. Sequelize.RANGE(Sequelize.BIGINT) // Defined int8range range. PostgreSQL only.
  34. Sequelize.RANGE(Sequelize.DATE) // Defines tstzrange range. PostgreSQL only.
  35. Sequelize.RANGE(Sequelize.DATEONLY) // Defines daterange range. PostgreSQL only.
  36. Sequelize.RANGE(Sequelize.DECIMAL) // Defines numrange range. PostgreSQL only.
  37. Sequelize.ARRAY(Sequelize.RANGE(Sequelize.DATE)) // Defines array of tstzrange ranges. PostgreSQL only.
  38. Sequelize.GEOMETRY // Spatial column. PostgreSQL (with PostGIS) or MySQL only.
  39. Sequelize.GEOMETRY('POINT') // Spatial column with geometry type. PostgreSQL (with PostGIS) or MySQL only.
  40. Sequelize.GEOMETRY('POINT', 4326) // Spatial column with geometry type and SRID. PostgreSQL (with PostGIS) or MySQL only.

BLOB数据类型允许您将数据作为字符串和二进制插入。 当您在具有BLOB列的模型上执行find或findAll时,该数据将始终作为二进制返回。

如果你正在使用PostgreSQL TIMESTAMP WITHOUT TIMEZONE,您需要将其解析为不同的时区,请使用pg库自己的解析器:

  1. require('pg').types.setTypeParser(1114, stringValue => {
  2. return new Date(stringValue + '+0000');
  3. // 例如UTC偏移。 使用你想要的任何偏移。
  4. });

除了上述类型之外,integer,bigint,float和double也支持unsigned和zerofill属性,可以按任何顺序组合:
请注意,这不适用于PostgreSQL!

  1. Sequelize.INTEGER.UNSIGNED // INTEGER UNSIGNED
  2. Sequelize.INTEGER(11).UNSIGNED // INTEGER(11) UNSIGNED
  3. Sequelize.INTEGER(11).ZEROFILL // INTEGER(11) ZEROFILL
  4. Sequelize.INTEGER(11).ZEROFILL.UNSIGNED // INTEGER(11) UNSIGNED ZEROFILL
  5. Sequelize.INTEGER(11).UNSIGNED.ZEROFILL // INTEGER(11) UNSIGNED ZEROFILL

上面的例子只显示整数,但是可以用bigint和float来完成

用对象表示法:

  1. // 对于枚举:
  2. sequelize.define('model', {
  3. states: {
  4. type: Sequelize.ENUM,
  5. values: ['active', 'pending', 'deleted']
  6. }
  7. })

Array(ENUM)

此项仅支持 PostgreSQL.

Array(ENUM) 类型需要特殊处理。 每当 Sequelize 与数据库通信时,它必须使用 ENUM 名称对数组值进行类型转换。

所以这个枚举名必须遵循 enum_<table_name>_<col_name> 这个模式。 如果您正在使用 sync,则会自动生成正确的名称。

范围类型

由于范围类型具有其绑定的包含(inclusive)/排除(exclusive)的额外信息,所以使用一个元组在javascript中表示它们并不是很简单。

将范围作为值提供时,您可以从以下API中进行选择:

  1. // 默认为 '["2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00")'
  2. // 包含下限, 排除上限
  3. Timeline.create({ range: [new Date(Date.UTC(2016, 0, 1)), new Date(Date.UTC(2016, 1, 1))] });
  4. // 控制包含
  5. const range = [new Date(Date.UTC(2016, 0, 1)), new Date(Date.UTC(2016, 1, 1))];
  6. range.inclusive = false; // '()'
  7. range.inclusive = [false, true]; // '(]'
  8. range.inclusive = true; // '[]'
  9. range.inclusive = [true, false]; // '[)'
  10. // 或作为单个表达式
  11. const range = [
  12. { value: new Date(Date.UTC(2016, 0, 1)), inclusive: false },
  13. { value: new Date(Date.UTC(2016, 1, 1)), inclusive: true },
  14. ];
  15. // '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00"]'
  16. // 复合形式
  17. const range = [
  18. { value: new Date(Date.UTC(2016, 0, 1)), inclusive: false },
  19. new Date(Date.UTC(2016, 1, 1)),
  20. ];
  21. // '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00")'
  22. Timeline.create({ range });

无论怎样, 请注意无论何时你接收到的返回值将会是是一个范围:

  1. // 储存的值: ("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00"]
  2. range // [Date, Date]
  3. range.inclusive // [false, true]

确保在序列化之前将其转换为可序列化的格式,因为数组额外的属性将不会被序列化。

特殊情况

  1. // 空范围:
  2. Timeline.create({ range: [] }); // range = 'empty'
  3. // 无限制范围:
  4. Timeline.create({ range: [null, null] }); // range = '[,)'
  5. // range = '[,"2016-01-01 00:00:00+00:00")'
  6. Timeline.create({ range: [null, new Date(Date.UTC(2016, 0, 1))] });
  7. // 无穷范围:
  8. // range = '[-infinity,"2016-01-01 00:00:00+00:00")'
  9. Timeline.create({ range: [-Infinity, new Date(Date.UTC(2016, 0, 1))] });

可延迟

当你在 PostgreSQL 中指定外键列的参数来声明成一个可延迟类型。 可用的选项如下:

  1. // 将所有外键约束检查推迟到事务结束时。
  2. Sequelize.Deferrable.INITIALLY_DEFERRED
  3. // 立即检查外键约束。
  4. Sequelize.Deferrable.INITIALLY_IMMEDIATE
  5. // 不要推迟检查。
  6. Sequelize.Deferrable.NOT

最后一个参数是 PostgreSQL 的默认值,不允许你在事务中动态的更改规则。 查看 the transaction section 获取补充信息.

Getters & setters

可以在模型上定义’对象属性’getter和setter函数,这些可以用于映射到数据库字段的“保护”属性,也可以用于定义“伪”属性。

Getters和Setters可以通过两种方式定义(您可以混合使用这两种方式):

  • 作为属性定义的一部分
  • 作为模型参数的一部分

注意: 如果在两个地方定义了getter或setter,那么在相关属性定义中找到的函数始终是优先的。

定义为属性定义的一部分

  1. const Employee = sequelize.define('employee', {
  2. name: {
  3. type: Sequelize.STRING,
  4. allowNull: false,
  5. get() {
  6. const title = this.getDataValue('title');
  7. // 'this' 允许你访问实例的属性
  8. return this.getDataValue('name') + ' (' + title + ')';
  9. },
  10. },
  11. title: {
  12. type: Sequelize.STRING,
  13. allowNull: false,
  14. set(val) {
  15. this.setDataValue('title', val.toUpperCase());
  16. }
  17. }
  18. });
  19. Employee
  20. .create({ name: 'John Doe', title: 'senior engineer' })
  21. .then(employee => {
  22. console.log(employee.get('name')); // John Doe (SENIOR ENGINEER)
  23. console.log(employee.get('title')); // SENIOR ENGINEER
  24. })

定义为模型参数的一部分

以下是在模型参数中定义 getter 和 setter 的示例。 fullName getter,是一个说明如何在模型上定义伪属性的例子 - 这些属性实际上不是数据库模式的一部分。 事实上,伪属性可以通过两种方式定义:使用模型getter,或者使用虚拟数据类型的列。 虚拟数据类型可以有验证,而虚拟属性的getter则不能。

请注意,fullName getter函数中引用的this.firstnamethis.lastname将触发对相应getter函数的调用。 如果你不想那样使用getDataValue()方法来访问原始值(见下文)。

  1. const Foo = sequelize.define('foo', {
  2. firstname: Sequelize.STRING,
  3. lastname: Sequelize.STRING
  4. }, {
  5. getterMethods: {
  6. fullName() {
  7. return this.firstname + ' ' + this.lastname
  8. }
  9. },
  10. setterMethods: {
  11. fullName(value) {
  12. const names = value.split(' ');
  13. this.setDataValue('firstname', names.slice(0, -1).join(' '));
  14. this.setDataValue('lastname', names.slice(-1).join(' '));
  15. },
  16. }
  17. });

用于 getter 和 setter 定义内部的 Helper 方法

  • 检索底层属性值 - 总是使用 this.getDataValue()
  1. /* 一个用于 'title' 属性的 getter */
  2. get() {
  3. return this.getDataValue('title')
  4. }
  • 设置基础属性值 - 总是使用 this.setDataValue()
  1. /* 一个用于 'title' 属性的 setter */
  2. set(title) {
  3. this.setDataValue('title', title.toString().toLowerCase());
  4. }

注意: 坚持使用 setDataValue()getDataValue() 函数(而不是直接访问底层的“数据值”属性)是非常重要的 - 这样做可以保护您的定制getter和setter不受底层模型实现的变化。

验证

模型验证,允许您为模型的每个属性指定格式/内容/继承验证。

验证会自动运行在 createupdatesave 上。 你也可以调用 validate() 手动验证一个实例。

验证由 validator.js 实现。

  1. const ValidateMe = sequelize.define('foo', {
  2. foo: {
  3. type: Sequelize.STRING,
  4. validate: {
  5. is: ["^[a-z]+$",'i'], // 只允许字母
  6. is: /^[a-z]+$/i, // 与上一个示例相同,使用了真正的正则表达式
  7. not: ["[a-z]",'i'], // 不允许字母
  8. isEmail: true, // 检查邮件格式 (foo@bar.com)
  9. isUrl: true, // 检查连接格式 (http://foo.com)
  10. isIP: true, // 检查 IPv4 (129.89.23.1) 或 IPv6 格式
  11. isIPv4: true, // 检查 IPv4 (129.89.23.1) 格式
  12. isIPv6: true, // 检查 IPv6 格式
  13. isAlpha: true, // 只允许字母
  14. isAlphanumeric: true, // 只允许使用字母数字
  15. isNumeric: true, // 只允许数字
  16. isInt: true, // 检查是否为有效整数
  17. isFloat: true, // 检查是否为有效浮点数
  18. isDecimal: true, // 检查是否为任意数字
  19. isLowercase: true, // 检查是否为小写
  20. isUppercase: true, // 检查是否为大写
  21. notNull: true, // 不允许为空
  22. isNull: true, // 只允许为空
  23. notEmpty: true, // 不允许空字符串
  24. equals: 'specific value', // 只允许一个特定值
  25. contains: 'foo', // 检查是否包含特定的子字符串
  26. notIn: [['foo', 'bar']], // 检查是否值不是其中之一
  27. isIn: [['foo', 'bar']], // 检查是否值是其中之一
  28. notContains: 'bar', // 不允许包含特定的子字符串
  29. len: [2,10], // 只允许长度在2到10之间的值
  30. isUUID: 4, // 只允许uuids
  31. isDate: true, // 只允许日期字符串
  32. isAfter: "2011-11-05", // 只允许在特定日期之后的日期字符串
  33. isBefore: "2011-11-05", // 只允许在特定日期之前的日期字符串
  34. max: 23, // 只允许值 <= 23
  35. min: 23, // 只允许值 >= 23
  36. isCreditCard: true, // 检查有效的信用卡号码
  37. // 也可以自定义验证:
  38. isEven(value) {
  39. if (parseInt(value) % 2 != 0) {
  40. throw new Error('Only even values are allowed!')
  41. // 我们也在模型的上下文中,所以如果它存在的话,
  42. // this.otherField会得到otherField的值。
  43. }
  44. }
  45. }
  46. }
  47. });

请注意,如果需要将多个参数传递给内置的验证函数,则要传递的参数必须位于数组中。 但是,如果要传递单个数组参数,例如isIn的可接受字符串数组,则将被解释为多个字符串参数,而不是一个数组参数。 要解决这个问题,传递一个单一长度的参数数组,比如[['one','two']]

要使用自定义错误消息而不是 validator.js 提供的错误消息,请使用对象而不是纯值或参数数组,例如不需要参数的验证器可以被给定自定义消息:

  1. isInt: {
  2. msg: "Must be an integer number of pennies"
  3. }

或者如果还需要传递参数,请添加一个args属性:

  1. isIn: {
  2. args: [['en', 'zh']],
  3. msg: "Must be English or Chinese"
  4. }

当使用自定义验证器函数时,错误消息将是抛出的Error对象所持有的任何消息。

有关内置验证方法的更多详细信息,请参阅the validator.js project

提示: 您还可以为日志记录部分定义自定义函数。 只是传递一个方法。 第一个参数将是记录的字符串。

验证器 与 allowNull

如果模型的特定字段设置为允许null(使用allowNull:true),并且该值已设置为null,则其验证器不会运行。 这意味着你可以有一个字符串字段来验证其长度至少为5个字符,但也允许null

模型验证

验证器也可以在特定字段验证器之后用来定义检查模型。例如,你可以确保纬度经度都不设置,或者两者都设置,如果设置了一个而另一个未设置则验证失败。

模型验证器方法与模型对象的上下文一起调用,如果它们抛出错误,则认为失败,否则通过。 这与自定义字段特定的验证器一样。

所收集的任何错误消息都将与验证结果对象一起放在字段验证错误中,这个错误使用在validate参数对象中以失败的验证方法的键来命名。即便在任何一个时刻,每个模型验证方法只能有一个错误消息,它会在数组中显示为单个字符串错误,以最大化与字段错误的一致性。

一个例子:

  1. const Pub = Sequelize.define('pub', {
  2. name: { type: Sequelize.STRING },
  3. address: { type: Sequelize.STRING },
  4. latitude: {
  5. type: Sequelize.INTEGER,
  6. allowNull: true,
  7. defaultValue: null,
  8. validate: { min: -90, max: 90 }
  9. },
  10. longitude: {
  11. type: Sequelize.INTEGER,
  12. allowNull: true,
  13. defaultValue: null,
  14. validate: { min: -180, max: 180 }
  15. },
  16. }, {
  17. validate: {
  18. bothCoordsOrNone() {
  19. if ((this.latitude === null) !== (this.longitude === null)) {
  20. throw new Error('Require either both latitude and longitude or neither')
  21. }
  22. }
  23. }
  24. })

在这种简单情况下,如果给定纬度或经度,而不是同时包含两者,则验证失败。 如果我们尝试构建一个超范围的纬度和经度,那么raging_bullock_arms.validate()可能会返回

  1. {
  2. 'latitude': ['Invalid number: latitude'],
  3. 'bothCoordsOrNone': ['Require either both latitude and longitude or neither']
  4. }

配置

你还可以修改 Sequelize 处理列名称的方式:

  1. const Bar = sequelize.define('bar', { /* bla */ }, {
  2. // 不添加时间戳属性 (updatedAt, createdAt)
  3. timestamps: false,
  4. // 不删除数据库条目,但将新添加的属性deletedAt设置为当前日期(删除完成时)。
  5. // paranoid 只有在启用时间戳时才能工作
  6. paranoid: true,
  7. // 不使用驼峰样式自动添加属性,而是下划线样式,因此updatedAt将变为updated_at
  8. underscored: true,
  9. // 禁用修改表名; 默认情况下,sequelize将自动将所有传递的模型名称(define的第一个参数)转换为复数。 如果你不想这样,请设置以下内容
  10. freezeTableName: true,
  11. // 定义表的名称
  12. tableName: 'my_very_custom_table_name',
  13. // 启用乐观锁定。 启用时,sequelize将向模型添加版本计数属性,
  14. // 并在保存过时的实例时引发OptimisticLockingError错误。
  15. // 设置为true或具有要用于启用的属性名称的字符串。
  16. version: true
  17. })

如果你希望sequelize处理时间戳,但只想要其中一部分,或者希望您的时间戳被称为别的东西,则可以单独覆盖每个列:

  1. const Foo = sequelize.define('foo', { /* bla */ }, {
  2. // 不要忘记启用时间戳!
  3. timestamps: true,
  4. // 我不想要 createdAt
  5. createdAt: false,
  6. // 我想 updateAt 实际上被称为 updateTimestamp
  7. updatedAt: 'updateTimestamp',
  8. // 并且希望 deletedA t被称为 destroyTime(请记住启用paranoid以使其工作)
  9. deletedAt: 'destroyTime',
  10. paranoid: true
  11. })

您也可以更改数据库引擎,例如 变更到到MyISAM, 默认值是InnoDB。

  1. const Person = sequelize.define('person', { /* attributes */ }, {
  2. engine: 'MYISAM'
  3. })
  4. // 或全局的
  5. const sequelize = new Sequelize(db, user, pw, {
  6. define: { engine: 'MYISAM' }
  7. })

最后,您可以为MySQL和PG中的表指定注释

  1. const Person = sequelize.define('person', { /* attributes */ }, {
  2. comment: "I'm a table comment!"
  3. })

导入

您还可以使用import方法将模型定义存储在单个文件中。 返回的对象与导入文件的功能中定义的完全相同。 由于Sequelizev1:5.0的导入是被缓存的,所以当调用文件导入两次或更多次时,不会遇到问题。

  1. // 在你的服务器文件中 - 例如 app.js
  2. const Project = sequelize.import(__dirname + "/path/to/models/project")
  3. // 模型已经在 /path/to/models/project.js 中定义好
  4. // 你可能会注意到,DataTypes与上述相同
  5. module.exports = (sequelize, DataTypes) => {
  6. return sequelize.define("project", {
  7. name: DataTypes.STRING,
  8. description: DataTypes.TEXT
  9. })
  10. }

import方法也可以接受回调作为参数。

  1. sequelize.import('project', (sequelize, DataTypes) => {
  2. return sequelize.define("project", {
  3. name: DataTypes.STRING,
  4. description: DataTypes.TEXT
  5. })
  6. })

这个额外的功能也是有用的, 例如 Error: Cannot find module 被抛出,即使 /path/to/models/project 看起来是正确的。 一些框架,如 Meteor,重载 require,并给出“惊喜”的结果,如:

  1. Error: Cannot find module '/home/you/meteorApp/.meteor/local/build/programs/server/app/path/to/models/project.js'

这通过传入Meteor的require版本来解决. 所以,虽然这可能会失败 …

  1. const AuthorModel = db.import('./path/to/models/project');

… 这应该是成功的 …

  1. const AuthorModel = db.import('project', require('./path/to/models/project'));

乐观锁定

Sequelize 内置支持通过模型实例版本计数的乐观锁定。

默认情况下禁用乐观锁定,可以通过在特定模型定义或全局模型配置中将version属性设置为true来启用。 有关详细信息,请参阅模型配置

乐观锁定允许并发访问模型记录以进行编辑,并防止冲突覆盖数据。 它通过检查另一个进程是否已经读取记录而进行更改,并在检测到冲突时抛出一个OptimisticLockError。

数据库同步

当开始一个新的项目时,你还不会有一个数据库结构,并且使用Sequelize你也不需要它。 只需指定您的模型结构,并让库完成其余操作。 目前支持的是创建和删除表:

  1. // 创建表:
  2. Project.sync()
  3. Task.sync()
  4. // 强制创建!
  5. Project.sync({force: true}) // 这将先丢弃表,然后重新创建它
  6. // 删除表:
  7. Project.drop()
  8. Task.drop()
  9. // 事件处理:
  10. Project.[sync|drop]().then(() => {
  11. // 好吧...一切都很好!
  12. }).catch(error => {
  13. // oooh,你输入了错误的数据库凭据?
  14. })

因为同步和删除所有的表可能要写很多行,你也可以让Sequelize来为做这些:

  1. // 同步所有尚未在数据库中的模型
  2. sequelize.sync()
  3. // 强制同步所有模型
  4. sequelize.sync({force: true})
  5. // 删除所有表
  6. sequelize.drop()
  7. // 广播处理:
  8. sequelize.[sync|drop]().then(() => {
  9. // woot woot
  10. }).catch(error => {
  11. // whooops
  12. })

因为.sync({ force: true })是具有破坏性的操作,可以使用match参数作为附加的安全检查。

match参数可以通知Sequelize,以便在同步之前匹配正则表达式与数据库名称 - 在测试中使用force:true但不使用实时代码的情况下的安全检查。

  1. // 只有当数据库名称以'_test'结尾时,才会运行.sync()
  2. sequelize.sync({ force: true, match: /_test$/ });

扩展模型

Sequelize 模型是ES6类。 您可以轻松添加自定义实例或类级别的方法。

  1. const User = sequelize.define('user', { firstname: Sequelize.STRING });
  2. // 添加一个类级别的方法
  3. User.classLevelMethod = function() {
  4. return 'foo';
  5. };
  6. // 添加实例级别方法
  7. User.prototype.instanceLevelMethod = function() {
  8. return 'bar';
  9. };

当然,您还可以访问实例的数据并生成虚拟的getter:

  1. const User = sequelize.define('user', { firstname: Sequelize.STRING, lastname: Sequelize.STRING });
  2. User.prototype.getFullname = function() {
  3. return [this.firstname, this.lastname].join(' ');
  4. };
  5. // 例子:
  6. User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar'

索引

Sequelize支持在 Model.sync()sequelize.sync 中创建的模型定义中添加索引。

  1. sequelize.define('user', {}, {
  2. indexes: [
  3. // 在 email 上创建一个唯一索引
  4. {
  5. unique: true,
  6. fields: ['email']
  7. },
  8. // 在使用 jsonb_path_ops 的 operator 数据上创建一个 gin 索引
  9. {
  10. fields: ['data'],
  11. using: 'gin',
  12. operator: 'jsonb_path_ops'
  13. },
  14. // 默认的索引名将是 [table]_[fields]
  15. // 创建多列局部索引
  16. {
  17. name: 'public_by_author',
  18. fields: ['author', 'status'],
  19. where: {
  20. status: 'public'
  21. }
  22. },
  23. // 具有有序字段的BTREE索引
  24. {
  25. name: 'title_index',
  26. method: 'BTREE',
  27. fields: ['author', {attribute: 'title', collate: 'en_US', order: 'DESC', length: 5}]
  28. }
  29. ]
  30. })