Sequelize-nodejs-3-model definition
Model definition模型定义
To define mappings between a model and a table, use the define
method.定义模型和表之间的映射,使用定义方法
即project表的模型定义为有两个字段title和description,并且其值属性为STRING和TEXT
const Project = sequelize.define('project', {
title: Sequelize.STRING,
description: Sequelize.TEXT
})
const Task = sequelize.define('task', {
title: Sequelize.STRING,
description: Sequelize.TEXT,
deadline: Sequelize.DATE
})
You can also set some options on each column:
const Foo = sequelize.define('foo', {
// 如果没有设置,实例化将自动设置flag为true
flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true },
// default values for dates => current time
myDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },
//allowNull设置为false将为每一列添加NOT NULL的设置,这意味着在执行查询时,如果列是空的,将从数据库抛出一个错误。
//如果你想在查询数据库之前检查一个值非空,看看下面的validations部分。
title: { type: Sequelize.STRING, allowNull: false },
//创建两个对象具有相同的值将抛出一个错误
//独特的属性可以是一个布尔值,或一个字符串
//如果你提供多个列相同的字符串,它们将形成一个复合唯一键。
uniqueOne: { type: Sequelize.STRING, unique: 'compositeIndex' },
uniqueTwo: { type: Sequelize.INTEGER, unique: 'compositeIndex' },
// The unique property is simply a shorthand to create a unique constraint.独特的性质只是一个速记创建唯一约束
someUnique: { type: Sequelize.STRING, unique: true },
// 这与在模型选项中创建索引是完全相同的.
{ someUnique: { type: Sequelize.STRING } },
{ indexes: [ { unique: true, fields: [ 'someUnique' ] } ] },//field既存储在表中的键名
//继续读取更多与主键相关内容
identifier: { type: Sequelize.STRING, primaryKey: true },
// autoIncrement可以用来创建auto_incrementing数列
incrementMe: { type: Sequelize.INTEGER, autoIncrement: true },
//您可以通过“字段”属性指定一个自定义字段名
fieldWithUnderscores: { type: Sequelize.STRING, field: 'field_with_underscores' },
//创建外键是可能的:
bar_id: {
type: Sequelize.INTEGER,
references: {
// 另一个模型的引用
model: Bar,
// 引用模型的列名
key: 'id',
//声明什么时候去查看外键约束,只用于PostgreSQL
deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
}
}
})
The comment option can also be used on a table, see model configuration
Timestamps
By default, Sequelize will add the attributes createdAt
and updatedAt
to your model so you will be able to know when the database entry went into the db and when it was updated last.
默认情况下,Sequelize将添加属性createdAt和updatedAt到你的模型,这样你就可以知道什么时候进了db数据库条目,和它最后更新的时间
Note that if you are using Sequelize migrations you will need to add the createdAt
and updatedAt
fields to your migration definition:
请注意,如果您使用的是Sequelize继承需要createdAt和updatedAt字段添加到你继承的定义中:
module.exports = {
up(queryInterface, Sequelize) {
return queryInterface.createTable('my-table', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
// Timestamps
createdAt: Sequelize.DATE,
updatedAt: Sequelize.DATE,
})
},
down(queryInterface, Sequelize) {
return queryInterface.dropTable('my-table');
},
}
If you do not want timestamps on your models, only want some timestamps, or you are working with an existing database where the columns are named something else, jump straight on to configuration to see how to do that.
如果你不希望在你的模型中使用时间戳,只需要一些时间戳,或者你正在为一个现有的列正重新命名的数据库工作,那么就直接跳转 configuration(下面会写)看看怎么做。
Data types
Below are some of the datatypes supported by sequelize. For a full and updated list, see DataTypes.
下面是sequelize支持的数据类型
Sequelize.STRING // VARCHAR(255)
Sequelize.STRING(1234) // VARCHAR(1234)
Sequelize.STRING.BINARY // VARCHAR BINARY
Sequelize.TEXT // TEXT
Sequelize.TEXT('tiny') // TINYTEXT
Sequelize.INTEGER // INTEGER
Sequelize.BIGINT // BIGINT
Sequelize.BIGINT(11) // BIGINT(11)
Sequelize.FLOAT // FLOAT
Sequelize.FLOAT(11) // FLOAT(11)
Sequelize.FLOAT(11, 12) // FLOAT(11,12)
Sequelize.REAL // REAL PostgreSQL only.
Sequelize.REAL(11) // REAL(11) PostgreSQL only.
Sequelize.REAL(11, 12) // REAL(11,12) PostgreSQL only.
Sequelize.DOUBLE // DOUBLE
Sequelize.DOUBLE(11) // DOUBLE(11)
Sequelize.DOUBLE(11, 12) // DOUBLE(11,12)
Sequelize.DECIMAL // DECIMAL
Sequelize.DECIMAL(10, 2) // DECIMAL(10,2)
Sequelize.DATE // DATETIME for mysql / sqlite, TIMESTAMP WITH TIME ZONE for postgres
Sequelize.DATE(6) // DATETIME(6) for mysql 5.6.4+. Fractional seconds support with up to 6 digits of precision
Sequelize.DATEONLY // DATE without time.
Sequelize.BOOLEAN // TINYINT(1)
Sequelize.ENUM('value 1', 'value 2') // An ENUM with allowed values 'value 1' and 'value 2'
Sequelize.ARRAY(Sequelize.TEXT) // Defines an array. PostgreSQL only.
Sequelize.ARRAY(Sequelize.ENUM) // Defines an array of ENUM. PostgreSQL only.
Sequelize.JSON // JSON column. PostgreSQL, SQLite and MySQL only.
Sequelize.JSONB // JSONB column. PostgreSQL only.
Sequelize.BLOB // BLOB (bytea for PostgreSQL)
Sequelize.BLOB('tiny') // TINYBLOB (bytea for PostgreSQL. Other options are medium and long)
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)
Sequelize.CIDR // CIDR datatype for PostgreSQL
Sequelize.INET // INET datatype for PostgreSQL
Sequelize.MACADDR // MACADDR datatype for PostgreSQL
Sequelize.RANGE(Sequelize.INTEGER) // Defines int4range range. PostgreSQL only.
Sequelize.RANGE(Sequelize.BIGINT) // Defined int8range range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DATE) // Defines tstzrange range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DATEONLY) // Defines daterange range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DECIMAL) // Defines numrange range. PostgreSQL only.
Sequelize.ARRAY(Sequelize.RANGE(Sequelize.DATE)) // Defines array of tstzrange ranges. PostgreSQL only.
Sequelize.GEOMETRY // Spatial column. PostgreSQL (with PostGIS) or MySQL only.
Sequelize.GEOMETRY('POINT') // Spatial column with geometry type. PostgreSQL (with PostGIS) or MySQL only.
Sequelize.GEOMETRY('POINT', 4326) // Spatial column with geometry type and SRID. PostgreSQL (with PostGIS) or MySQL only.
The BLOB data type allows you to insert data both as strings and as buffers. When you do a find or findAll on a model which has a BLOB column, that data will always be returned as a buffer.
BLOB数据类型允许你插入字符串和buffer。当你在有BLOB数据类型的列的模型中进行查找时,将会返回buffer
If you are working with the PostgreSQL TIMESTAMP WITHOUT TIME ZONE and you need to parse it to a different timezone, please use the pg library's own parser:
如果你使用PostgreSQL没有时区的时间戳,并且你需要将其解析到一个不同的时区,请用PostgreSQL库中自己的解析器
require('pg').types.setTypeParser(1114, stringValue => {
return new Date(stringValue + '+0000');
// e.g., UTC offset. Use any offset that you would like.
});
In addition to the type mentioned above, integer, bigint, float and double also support unsigned and zerofill properties, which can be combined in any order: Be aware that this does not apply for PostgreSQL!
除了上面提到的类型,整数,长整型数字,浮点数和双精度浮点数也支持无符号和补零属性,可以在任何顺序连接: 。请注意,这不用于PostgreSQL
Sequelize.INTEGER.UNSIGNED // INTEGER UNSIGNED
Sequelize.INTEGER(11).UNSIGNED // INTEGER(11) UNSIGNED
Sequelize.INTEGER(11).ZEROFILL // INTEGER(11) ZEROFILL
Sequelize.INTEGER(11).ZEROFILL.UNSIGNED // INTEGER(11) UNSIGNED ZEROFILL
Sequelize.INTEGER(11).UNSIGNED.ZEROFILL // INTEGER(11) UNSIGNED ZEROFILL
The examples above only show integer, but the same can be done with bigint and float
上面的示例只显示整数,但同样可以用长整型数字和浮动
Usage in object notation:用于对象
// for enums:
sequelize.define('model', {
states: {
type: Sequelize.ENUM,
values: ['active', 'pending', 'deleted']
}
})
Array(ENUM) - Its only supported with PostgreSQL.数组(枚举类型)只在PostgreSQL中支持
Array(Enum) type require special treatment. Whenever Sequelize will talk to database it has to typecast Array values with ENUM name.
So this enum name must follow this pattern enum_<table_name>_<col_name>
. If you are using sync
then correct name will automatically be generated.
Range types
Since range types have extra information for their bound inclusion/exclusion it's not very straightforward to just use a tuple to represent them in javascript.
因为范围类型对其边界的包含/排除(即开口和闭口)有额外信息,不容易在javascript中使用元组来表示它们。
When supplying ranges as values you can choose from the following APIs:
// defaults to '["2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00")'
// inclusive lower bound, exclusive upper bound,默认情况为下界为闭口[,上界为开口)
Timeline.create({ range: [new Date(Date.UTC(2016, 0, 1)), new Date(Date.UTC(2016, 1, 1))] });
// control inclusion,通过inclusive来设置开闭口
const range = [new Date(Date.UTC(2016, 0, 1)), new Date(Date.UTC(2016, 1, 1))];
range.inclusive = false; // '()'
range.inclusive = [false, true]; // '(]'
range.inclusive = true; // '[]'
range.inclusive = [true, false]; // '[)'
// or as a single expression
const range = [
{ value: new Date(Date.UTC(2016, 0, 1)), inclusive: false },
{ value: new Date(Date.UTC(2016, 1, 1)), inclusive: true },
];
// '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00"]'
// composite form
const range = [
{ value: new Date(Date.UTC(2016, 0, 1)), inclusive: false },
new Date(Date.UTC(2016, 1, 1)),
];
// '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00")'
Timeline.create({ range });
However, please note that whenever you get back a value that is range you will receive:
注意,你得到的结果也是range
// stored value: ("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00"]
range // [Date, Date]
range.inclusive // [false, true]
Make sure you turn that into a serializable format before serialization since array extra properties will not be serialized.
因为数组额外的属性不会被序列化,所以确保序列化之前你将其转换成了一个可序列化的格式。
Special Cases
// empty range:
Timeline.create({ range: [] }); // range = 'empty'
// Unbounded range:
Timeline.create({ range: [null, null] }); // range = '[,)',默认
// range = '[,"2016-01-01 00:00:00+00:00")'
Timeline.create({ range: [null, new Date(Date.UTC(2016, 0, 1))] });
// Infinite range:
// range = '[-infinity,"2016-01-01 00:00:00+00:00")'
Timeline.create({ range: [-Infinity, new Date(Date.UTC(2016, 0, 1))] });
Deferrable可延期的
When you specify a foreign key column it is optionally possible to declare the deferrable type in PostgreSQL. The following options are available:
当你指定一个外键列时,可以声明在PostgreSQL可延期的类型
// Defer all foreign key constraint check to the end of a transaction,将所有外键约束检查推迟到事务的最后
Sequelize.Deferrable.INITIALLY_DEFERRED
// Immediately check the foreign key constraints,马上检查外键约束
Sequelize.Deferrable.INITIALLY_IMMEDIATE
// Don't defer the checks at all,不推迟检查
Sequelize.Deferrable.NOT
The last option is the default in PostgreSQL and won't allow you to dynamically change the rule in a transaction.
最后一个选项在PostgreSQL上是默认的,不允许您动态地改变一个事务中的规则。
See the transaction section for further information.
Getters & setters
It is possible to define 'object-property' getters and setter functions on your models, these can be used both for 'protecting' properties that map to database fields and for defining 'pseudo' properties.
可以在你的模型中定义对象属性的getter和setter函数,这些都可以用以“保护”映射到数据库字段的属性和定义“伪”属性。
Getters and Setters can be defined in 2 ways (you can mix and match these 2 approaches)两种定义方法:
- as part of a single property definition作为一个属性定义的一部分
- as part of a model options作为一个模型的选项
N.B: If a getter or setter is defined in both places then the function found in the relevant property definition will always take precedence.如果一个getter或setter函数定义在两个地方然后发现在相关属性定义(即第一种方法)总是优先考虑。
Defining as part of a property(第一种方法)
const Employee = sequelize.define('employee', { name: { type: Sequelize.STRING, allowNull: false, get() { const title = this.getDataValue('title'); // 'this' allows you to access attributes of the instance return this.getDataValue('name') + ' (' + title + ')'; }, }, title: { type: Sequelize.STRING, allowNull: false, set(val) { this.setDataValue('title', val.toUpperCase()); } } }); Employee .create({ name: 'John Doe', title: 'senior engineer' }) .then(employee => { console.log(employee.get('name')); // John Doe (SENIOR ENGINEER) console.log(employee.get('title')); // SENIOR ENGINEER })
Defining as part of the model options(第二种方法)
Below is an example of defining the getters and setters in the model options. The fullName
getter, is an example of how you can define pseudo properties on your models - attributes which are not actually part of your database schema. In fact, pseudo properties can be defined in two ways: using model getters, or by using a column with the VIRTUAL
datatype. Virtual datatypes can have validations, while getters for virtual attributes cannot.
下面是一个例子,在模型选项中定义getter和setter方法。fullName这个getter是如何定义伪属性的一个示例模型——属性不是数据库模式的一部分。事实上,伪属性可以使用两种方法进行定义:使用模型的getter方法,或者通过使用带有一个虚拟数据类型的列。虚拟数据类型可以验证,而虚拟属性的getter方法不能。
Note that the this.firstname
and this.lastname
references in the fullName
getter function will trigger a call to the respective getter functions. If you do not want that then use the getDataValue()
method to access the raw value (see below).
注意在fullName
这个getter函数中引用的this.firstname
和this.lastname
将会触发相应的getter函数。如果你不希望getDataValue()方法去访问原始值,就可以使用this. *(见下文)。
const Foo = sequelize.define('foo', { firstname: Sequelize.STRING, lastname: Sequelize.STRING }, { getterMethods: { fullName() { return this.firstname + ' ' + this.lastname } }, setterMethods: { fullName(value) { const names = value.split(' '); this.setDataValue('firstname', names.slice(0, -1).join(' ')); this.setDataValue('lastname', names.slice(-1).join(' ')); }, } });
Helper functions for use inside getter and setter definitions
- retrieving an underlying property value - always use
this.getDataValue()使用
this.getDataValue()
获取一个基本属性值
/* a getter for 'title' property */ get() { return this.getDataValue('title') }
- setting an underlying property value - always use
this.setDataValue()使用
this.setDataValue()
设置一个基本属性值
/* a setter for 'title' property */ set(title) { this.setDataValue('title', title.toString().toLowerCase()); }
N.B: It is important to stick to using the setDataValue()
and getDataValue()
functions (as opposed to accessing the underlying "data values" property directly) - doing so protects your custom getters and setters from changes in the underlying model implementations.
坚持使用setDataValue()和 getDataValue()函数(而不是直接访问底层的“数据值”属性)是很重要的,这样做可以保护你自定义的getter和setter以免受到底层模型实现的变化的影响。
Validations验证
Model validations, allow you to specify format/content/inheritance validations for each attribute of the model.模型验证,允许您为每个模型的属性指定格式/内容/继承的验证。
Validations are automatically run on create
, update
and save
. You can also call validate()
to manually validate an instance.
验证自动运行在创建、更新和保存过程中。您还可以手动调用validate()来验证实例
The validations are implemented by validator.js.
const ValidateMe = sequelize.define('foo', { foo: { type: Sequelize.STRING, validate: { is: ["^[a-z]+$",'i'], // will only allow letters is: /^[a-z]+$/i, // same as the previous example using real RegExp not: ["[a-z]",'i'], // will not allow letters isEmail: true, // checks for email format (foo@bar.com) isUrl: true, // checks for url format (http://foo.com) isIP: true, // checks for IPv4 (129.89.23.1) or IPv6 format isIPv4: true, // checks for IPv4 (129.89.23.1) isIPv6: true, // checks for IPv6 format isAlpha: true, // will only allow letters isAlphanumeric: true, // will only allow alphanumeric characters, so "_abc" will fail isNumeric: true, // will only allow numbers isInt: true, // checks for valid integers isFloat: true, // checks for valid floating point numbers isDecimal: true, // checks for any numbers isLowercase: true, // checks for lowercase isUppercase: true, // checks for uppercase notNull: true, // won't allow null isNull: true, // only allows null notEmpty: true, // don't allow empty strings equals: 'specific value', // only allow a specific value contains: 'foo', // force specific substrings notIn: [['foo', 'bar']], // check the value is not one of these isIn: [['foo', 'bar']], // check the value is one of these notContains: 'bar', // don't allow specific substrings len: [2,10], // only allow values with length between 2 and 10 isUUID: 4, // only allow uuids isDate: true, // only allow date strings isAfter: "2011-11-05", // only allow date strings after a specific date isBefore: "2011-11-05", // only allow date strings before a specific date max: 23, // only allow values <= 23 min: 23, // only allow values >= 23 isCreditCard: true, // check for valid credit card numbers // custom validations are also possible: isEven(value) { if (parseInt(value) % 2 != 0) { throw new Error('Only even values are allowed!') // we also are in the model's context here, so this.otherField // would get the value of otherField if it existed } } } } });
Note that where multiple arguments need to be passed to the built-in validation functions, the arguments to be passed must be in an array. But if a single array argument is to be passed, for instance an array of acceptable strings for isIn
, this will be interpreted as multiple string arguments instead of one array argument. To work around this pass a single-length array of arguments, such as [['one', 'two']]
as shown above.
注意,在多个参数需要被传递给的内置的验证函数中,被传递的参数必须是一个数组。但如果传递的是单个数组参数,例如在isIn
中设置为可接受的字符串数组,这将被视为多个字符串参数,而不是单个数组参数。用以解决传递单个长度参数的数组,如上面所举例子[['one', 'two']]
。
To use a custom error message instead of that provided by validator.js, use an object instead of the plain value or array of arguments, for example a validator which needs no argument can be given a custom message with
使用自定义的错误消息而不是提供的validator.js,使用对象来替代plain value或参数数组,比如不需要参数的验证器可以给一个如下面的定制的消息:
isInt: { msg: "Must be an integer number of pennies" }
or if arguments need to also be passed add an args
property:
或如果参数需要被传递,那就添加一个args
属性
isIn: { args: [['en', 'zh']], msg: "Must be English or Chinese" }
When using custom validator functions the error message will be whatever message the thrown Error
object holds.
当使用自定义验证器函数,错误消息将是抛出的错误对象中的任何消息
See the validator.js project for more details on the built in validation methods.
Hint: You can also define a custom function for the logging part. Just pass a function. The first parameter will be the string that is logged.
您还可以定义一个自定义函数用以记录。仅仅通过一个函数。第一个参数是记录的字符串
Validators and allowNull
If a particular field of a model is set to allow null (with allowNull: true
) and that value has been set to null
, its validators do not run. This means you can, for instance, have a string field which validates its length to be at least 5 characters, but which also allows null
.
如果一个特定领域模型设置为允许null(allowNull:真实),该值被设置为null,其验证器不运行。举例来说,这意味着您可以有一个验证字符串字段的长度至少5个字符,但是也allowsnull。
如果模型的特定字段被设置为允许null(有着设置allowNull: true
),则其值将会被设置诶null,验证器将不会运行。举例来说,这意味着您可以有一个字符串字段验证其长度至少5个字符,但是同时也允许其值为null。
Model validations
Validations can also be defined to check the model after the field-specific validators. Using this you could, for example, ensure either neither of latitude
and longitude
are set or both, and fail if one but not the other is set.
验证也可以在具体字段的验证器后被定义去检查模型(如下面例子的bothCoordsOrNone函数就是在latitude
和longitude
具体字段验证器后定义的验证)。例如,使用这个可以确保要么latitude
和longitude
都没有被设置或两者都被设置,如果一个设置而另一个没有则失败(下面的例子)
Model validator methods are called with the model object's context and are deemed to fail if they throw an error, otherwise pass. This is just the same as with custom field-specific validators.
模型验证器方法与模型对象的上下文一起被调用,并抛出错误则认为失败,否则通过。这与自定义具体字段的验证器是相同的。
Any error messages collected are put in the validation result object alongside the field validation errors, with keys named after the failed validation method's key in the validate
option object. Even though there can only be one error message for each model validation method at any one time, it is presented as a single string error in an array, to maximize consistency with the field errors.
收集的任何错误消息将被放到带着验证错误字段的验证结果对象中,并带着在验证选项对象中经过失败的验证方法的键值后命名的键值。即使在任何时候,对于每个模型验证方法只能有一个错误信息,它是作为在数组中的一个字符串错误,并最大化错误字段的一致性。
An example:
const Pub = Sequelize.define('pub', { name: { type: Sequelize.STRING }, address: { type: Sequelize.STRING }, latitude: { type: Sequelize.INTEGER, allowNull: true, defaultValue: null, validate: { min: -90, max: 90 } }, longitude: { type: Sequelize.INTEGER, allowNull: true, defaultValue: null, validate: { min: -180, max: 180 } }, }, { validate: { bothCoordsOrNone() { if ((this.latitude === null) !== (this.longitude === null)) { throw new Error('Require either both latitude and longitude or neither') } } } })
In this simple case an object fails validation if either latitude or longitude is given, but not both.
If we try to build one with an out-of-range latitude and no longitude, raging_bullock_arms.validate()
might return:如果创建超出范围的latitude并不设置longitude,则会报下面的错:
{ 'latitude': ['Invalid number: latitude'], 'bothCoordsOrNone': ['Require either both latitude and longitude or neither'] }
Configuration
You can also influence the way Sequelize handles your column names:
影响Sequelize处理你的列名的方式
const Bar = sequelize.define('bar', { /* bla */ }, { // 不添加时间戳属性(updatedAt, createdAt) timestamps: false, // 不删除数据库的条目,但是在目前的日期中添加deletedAt属性,在delete完成时,即(updatedAt, createdAt, deletedAt) // paranoid只在timestamps为true时可用 paranoid: true, //自动添加属性将不使用camelcase(一种拼写法),而是使用下划线风格 //即从updatedAt变为updated_at underscored: true, //即不允许表名的修改 //默认情况下,sequelize将会自动将通过的模型名(即定义的第一个参数)转成复数形式 //如果你不想这么做,就进行下面的设置 freezeTableName: true, // define the table's name,定义表名 tableName: 'my_very_custom_table_name', //Enable optimistic locking(下面有说) //当enabled时,sequelize将添加版本计数属性到模型上,并在失效实例被保存时抛出OptimisticLockingError错误 //当你想要enable optimistic locking时,将其设置为true或带有属性名的字符串 version: true })
If you want sequelize to handle timestamps, but only want some of them, or want your timestamps to be called something else, you can override each column individually:
如果你想要sequelize处理时间戳,但是有只想要时间戳的一部分(下面只要
),或者你想要时间戳能够被别的调用(下面设置为可被updatedAt
调用),你可以单独覆写每一列:updateTimestamp
const Foo = sequelize.define('foo', { /* bla */ }, { // don't forget to enable timestamps! timestamps: true, // I don't want createdAt createdAt: false, // I want updatedAt to actually be called updateTimestamp updatedAt: 'updateTimestamp', // And deletedAt to be called destroyTime (remember to enable paranoid for this to work) deletedAt: 'destroyTime', paranoid: true })
You can also change the database engine, e.g. to MyISAM. InnoDB is the default.
你也可以改变数据库引擎,默认是MyISAM. InnoDB
const Person = sequelize.define('person', { /* attributes */ }, { engine: 'MYISAM' }) // or globally const sequelize = new Sequelize(db, user, pw, { define: { engine: 'MYISAM' } })
Finally you can specify a comment for the table in MySQL and PG
最后你可以在MySQL和 PG数据库的表中发表评价
const Person = sequelize.define('person', { /* attributes */ }, { comment: "I'm a table comment!" })
Optimistic Locking
Sequelize has built-in support for optimistic locking through a model instance version count. Optimistic locking is disabled by default and can be enabled by setting the version
property to true in a specific model definition or global model configuration. See model configuration for more details.
Sequelize通过模型实例版本计数来内置支持optimistic locking(如上面的设置version: true)。Optimistic locking默认是不可用的,然后能够在具体模型定义或全局模型配置中通过设置version
属性为true来使其可行。
Optimistic locking allows concurrent access to model records for edits and prevents conflicts from overwriting data. It does this by checking whether another process has made changes to a record since it was read and throws an OptimisticLockError when a conflict is detected.
Optimistic locking允许并发访问用以编辑和防止覆盖数据的冲突的模型记录。它通过检查另一个进程是否在其读取时已更改记录和当检测到冲突时抛出一个OptimisticLockError来实现。
Import
You can also store your model definitions in a single file using the import
method. The returned object is exactly the same as defined in the imported file's function. Since v1:5.0
of Sequelize the import is cached, so you won't run into troubles when calling the import of a file twice or more often.
你可以使用import方法存储你的模型定义到一个文件中。返回对象与定义在导入文件的函数中的是相同的。从v1:5.0
版本开始Sequelize的导入为缓存,所以当你导入一个文件两次或更多次时,也不会导致问题出现
// in your server file - e.g. app.js const Project = sequelize.import(__dirname + "/path/to/models/project") // The model definition is done in /path/to/models/project.js // As you might notice, the DataTypes are the very same as explained above module.exports = (sequelize, DataTypes) => { return sequelize.define("project", { name: DataTypes.STRING, description: DataTypes.TEXT }) }
The import
method can also accept a callback as an argument.
import方法也接受回调函数作为参数
sequelize.import('project', (sequelize, DataTypes) => { return sequelize.define("project", { name: DataTypes.STRING, description: DataTypes.TEXT }) })
This extra capability is useful when, for example, Error: Cannot find module
is thrown even though /path/to/models/project
seems to be correct. Some frameworks, such as Meteor, overload require
, and spit out "surprise" results like :
Error: Cannot find module '/home/you/meteorApp/.meteor/local/build/programs/server/app/path/to/models/project.js'
This is solved by passing in Meteor's version of require
. So, while this probably fails ...
const AuthorModel = db.import('./path/to/models/project');
... this should succeed ...
const AuthorModel = db.import('project', require('./path/to/models/project'));
Database synchronization同步数据库
When starting a new project you won't have a database structure and using Sequelize you won't need to. Just specify your model structures and let the library do the rest. Currently supported is the creation and deletion of tables:
当开始一个新项目时,你还没有数据库且不需要使用Sequelize。只要指定你的模型结构,然后剩下的就让库去处理。
目前只支持创建和删除表:
之前已经定义了表的模型,调用.sync()将会创建表并且返回一个Promise对象
// Create the tables: Project.sync() Task.sync() // Force the creation! force: true将会删掉原来的表并重新生成表 Project.sync({force: true}) // this will drop the table first and re-create it afterwards // drop the tables:删除表 Project.drop() Task.drop() // event handling:监听sync|drop事件 Project.[sync|drop]().then(() => { // ok ... everything is nice! }).catch(error => { // oooh, did you enter wrong database credentials? })
Because synchronizing and dropping all of your tables might be a lot of lines to write, you can also let Sequelize do the work for you:
因为同步或删除你的所有表将需要写很多行,你可以让Sequelize帮你做这件事:
// Sync all models that aren't already in the database sequelize.sync() // Force sync all models sequelize.sync({force: true}) // Drop all tables sequelize.drop() // emit handling: sequelize.[sync|drop]().then(() => { // woot woot }).catch(error => { // whooops })
Because .sync({ force: true })
is destructive operation, you can use match
option as an additional safety check. match
option tells sequelize to match a regex against the database name before syncing - a safety check for cases where force: true
is used in tests but not live code.
因为.sync({ force: true })
是毁灭性操作,你可以使用match
选项作为额外安全检查。match
选项告诉sequelize在同步前去匹配与数据库名字相关的正则表达式-它是当例子设置为force: true
时的安全性的检查,只用于测试,而不是代码
// This will run .sync() only if database name ends with '_test' sequelize.sync({ force: true, match: /_test$/ });
Expansion of models模型扩展
Sequelize Models are ES6 classes. You can very easily add custom instance or class level methods.
Sequelize模型是ES6类。你可以很容易地添加自定义实例级或者类级方法
const User = sequelize.define('user', { firstname: Sequelize.STRING }); // Adding a class level method,类级 User.classLevelMethod = function() { return 'foo'; }; // Adding an instance level method,实例级 User.prototype.instanceLevelMethod = function() { return 'bar'; };
Of course you can also access the instance's data and generate virtual getters:
你可以访问实例数据和生成虚拟getters函数:
const User = sequelize.define('user', { firstname: Sequelize.STRING, lastname: Sequelize.STRING }); User.prototype.getFullname = function() { return [this.firstname, this.lastname].join(' '); }; // Example: User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar'
Indexes索引
Sequelize supports adding indexes to the model definition which will be created during Model.sync()
or sequelize.sync
.
Sequelize支持为将要在 Model.sync()
或sequelize.sync中创建的模型定义
添加索引
sequelize.define('user', {}, { indexes: [ // Create a unique index on email { unique: true, fields: ['email'] }, // Creates a gin index on data with the jsonb_path_ops operator { fields: ['data'], using: 'gin', operator: 'jsonb_path_ops' }, // By default index name will be [table]_[fields] // Creates a multi column partial index { name: 'public_by_author', fields: ['author', 'status'], where: { status: 'public' } }, // A BTREE index with a ordered field { name: 'title_index', method: 'BTREE', fields: ['author', {attribute: 'title', collate: 'en_US', order: 'DESC', length: 5}] } ] })