定义
定义模型与表之间的映射,使用 define 方法.
Sequelize 会自动增加 createdAt
和 updated
属性,这样能知道一个实例的创建时间和最终修改时间.如果不想自动生成,可以到configuration去看如何实现.
var Project = sequelize.define('project', {
title: Sequelize.STRING,
description: Sequelize.TEXT
})
var Task = sequelize.define('task', {
title: Sequelize.STRING,
description: Sequelize.TEXT,
deadline: Sequelize.DATE
})
还可以为每一个列增加一些可选属性
var Foo = sequelize.define('foo', {
// 自动设置默认值为 true
flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true},
// 日期默认值 => 当前时间
myDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },
// 设置列的 allowNull为 false 将会为该列增加 非空 属性
// 在查询数据库之前想检车一个值是否为 空 ,看 validation 节
title: { type: Sequelize.STRING, allowNull: false},
// 创建两个拥有相同属性的值会抛出一个错误
// The unique property can be either a boolean, or a string.
// If you provide the same string for multiple columns, they will form a
// composite unique key.
someUnique: {type: Sequelize.STRING, unique: true},
uniqueOne: { type: Sequelize.STRING, unique: 'compositeIndex'},
uniqueTwo: { type: Sequelize.INTEGER, unique: 'compositeIndex'}
// unique 属性同时也是创建一个 unique 索引 的简写
someUnique: {type: Sequelize.STRING, unique: true}
// 跟下面的两句定义语句等价
{someUnique: {type: Sequelize.STRING}},
{indexes: [{unique: true, fields: ['someUnique']}]}
// 主码
identifier: { type: Sequelize.STRING, primaryKey: true},
// 自增
incrementMe: { type: Sequelize.INTEGER, autoIncrement: true },
// 注释,只有 MySQL 和 PG 可以使用
// Comments can be specified for each field for MySQL and PG
hasComment: { type: Sequelize.INTEGER, comment: "I'm a comment!" },
// 在模型中的名字是小驼峰,在表中的列名可以用 field 属性来指定
fieldWithUnderscores: { type: Sequelize.STRING, field: "field_with_underscores" },
// 创建外码
bar_id: {
type: Sequelize.INTEGER,
references: {
// This is a reference to another model
model: Bar,
//被引用模型的 列名 (是列名,即 field 名)
key: 'id',
// 检查外码约束,只支持 PostgreSQL .
deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
}
}
})
数据类型
更详细的可以上 DataTypes 看一看
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.JSON // JSON column. PostgreSQL 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.GEOMETRY // Spatial column. PostgreSQL (with PostGIS) or MySQL only.
Sequelize.GEOMETRY('POINT') // Spatial column with geomerty type. PostgreSQL (with PostGIS) or MySQL only.
Sequelize.GEOMETRY('POINT', 4326) // Spatial column with geomerty type and SRID. PostgreSQL (with PostGIS) or MySQL only.
integer, bigint, float 和 double 同样支持 unsigned 和 zerofill 约束
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
对象标记的用法
// for enums:
sequelize.define('model', {
states: {
type: Sequelize.ENUM,
values: ['active', 'pending', 'deleted']
}
})
Getters & Setters 方法
在模型中定义'对象-属性'的 getter 和 setter 方法是可能的,可以被用来保护与数据库列相映射的属性,还可以定义一些假
属性
Getters 和 Setters 能以下面两种方式定义
- 作为单个属性定义的一部分
- 作为模型可选的一部分
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.
定义为属性的一部分
var Employee = sequelize.define('employee', {
name: {
type : Sequelize.STRING,
allowNull: false,
get : function() {
var title = this.getDataValue('title');
// 'this' 允许你去获得实例的属性
return this.getDataValue('name') + ' (' + title + ')';
},
},
title: {
type : Sequelize.STRING,
allowNull: false,
set : function(val) {
this.setDataValue('title', val.toUpperCase());
}
}
});
Employee
.create({ name: 'John Doe', title: 'senior engineer' })
.then(function(employee) {
console.log(employee.get('name')); // John Doe (SENIOR ENGINEER)
console.log(employee.get('title')); // SENIOR ENGINEER
})
定义为模型的一部分
下面是一个在模型内定义 getter 和 setter 方法的例子. 在这个例子里,fullname
的 getter 方法是在模型内定义假属性
的一个例子
,因为 fullname
属性不存在于数据库模式中. 实际上,假属性可以通过以下两种方式来定义
- 通过模型的 getter 方法
- 或者通过使用带有
VIRTUAL
数据类型的列, VIRTUAL 数据类型可以有 validation , 然而 virtual 数据类型的 getter 方法不行
注意在 fullName
的 getter 方法中引用的 this.firstName
和 this.lastName
会触发各自的 getter 方法
var Foo = sequelize.define('foo', {
firstname: Sequelize.STRING,
lastname: Sequelize.STRING
}, {
getterMethods : {
fullName : function() { return this.firstname + ' ' + this.lastname }
},
setterMethods : {
fullName : function(value) {
var names = value.split(' ');
this.setDataValue('firstname', names.slice(0, -1).join(' '));
this.setDataValue('lastname', names.slice(-1).join(' '));
},
}
});
在 getter 和 setter 方法中使用的 Helper 方法
- 获取一个基础属性值 , 经常用
this.getDataValue()
- 设置一个基础属性值 , 经常用
this.setDataValue()
- 坚持使用 getter 和 setter 方法 可以保护内部数据
/* 'title' 属性的 getter 方法*/
function(){
return this.getDataValue('title');
}
/* 'title' 属性的 setter 方法*/
function(){
return this.setDataValue('title',title.toString().toLowerCase());
}
认证 (Validation)
模型认证, 可以规定模型中每个属性的格式/内容 的认证. 其实现在这
当进行 create
,update
和 save
操作时,认证会自动运行.也可以在实例中手动认证
var 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
min: 23, // only allow values >= 23
isArray: true, // only allow arrays
isCreditCard: true, // check for valid credit card numbers
// custom validations are also possible:
isEven: function(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
}
}
}
}
});
注意当多个参数需要被传递到内嵌的认证函数时,多个参数应该被放在一个数组中.
isIn: [['en', 'zh']], // check the value is one of these
不用 validator.js 提供的错误信息,自己定制错误信息
isIn: {
args: [['en', 'zh']],
msg: "Must be English or Chinese"
}
可以看validator.js PROJECT获取更多细节
认证器和 allowNull
如果模型的列被设置为 allowNull:true
和 值被设置为 null
的话,那认证器不会运行.
举个栗子, 一个字符串的列长度设置为 最短为5, 但它可以存储 null
模型认证
var 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 }
},
}, {
//在这里对模型进行验证,只有 latitude 和 longtitude 同时被给予或都为空时成立
validate: {
bothCoordsOrNone: function() {
if ((this.latitude === null) !== (this.longitude === null)) {
throw new Error('Require either both latitude and longitude or neither')
}
}
}
})
配置
var Bar = sequelize.define('bar', { /* bla */ }, {
// 不增加 TIMESTAMP 属性 (updatedAt, createdAt)
timestamps: false,
//不删除数据库中原有项, 增加新属性 deletedAt 并设置为 当前日期,
//只有 TIMESTAMP 属性是允许的时候有效
paranoid: true,
// 不要使用驼峰式语法,用下划线代替
// so updatedAt will be updated_at
underscored: true,
// 不允许调整表名 ;
// 默认地, sequelize 会自动转换所有传递的模型名字(define 的第一个参数)
// 为复数
// 如果不想这样,设置为 true
freezeTableName: true,
// 定义表名
tableName: 'my_very_custom_table_name'
})
修改引擎
var Person = sequelize.define('person', { /* attributes */ }, {
engine: 'MYISAM'
})
// or globally
var sequelize = new Sequelize(db, user, pw, {
define: { engine: 'MYISAM' }
})
做注释
var Person = sequelize.define('person', { /* attributes */ }, {
comment: "I'm a table comment!"
})
导入
可以把对表的定义放在单一文件中,返回对象恰好跟在 import 方法中定义的一样
// in your server file - e.g. app.js
var Project = sequelize.import(__dirname + "/path/to/models/project")
// 定义在 project.js 文件中已经定义完成了
// DataTypes 与上面解释的部分很像
module.exports = function(sequelize, DataTypes) {
return sequelize.define("project", {
name: DataTypes.STRING,
description: DataTypes.TEXT
})
}
sequelize.import('project', function(sequelize, DataTypes) {
return sequelize.define("project", {
name: DataTypes.STRING,
description: DataTypes.TEXT
})
})
数据库同步
开始一个新项目的时候,我们没有数据库架构,于是我们不需要 Sequelize.
只需要说明我们的模型结构, 让库做剩下的部分,现在只支持 表的创建与删除
// 只同步还没在数据库中的模型
// Sync all models that aren't already in the database
sequelize.sync()
// 强制同步所有数据库的模型
sequelize.sync({force: true})
// 删除所有表
sequelize.drop()
// 开始执行
sequelize.[sync|drop]().then(function() {
// woot woot
}).catch(function(error) {
// whooops
})
因为.sync({force: true})
是毁灭性的操作, 可以使用 match 选项去增加更多的安全检查(正则)
// 删除以 '_test' 结尾的词
sequelize.sync({ force: true, match: /_test$/ });
模型的扩展
Sequelize 允许我们去给 模型和相应的实例 传递定制方法
var sequelize = new Sequelize('database', 'username', 'password', {
// 其他可选的初始化可以放在这里
define: {
classMethods: {
method1: function() {},
method2: function() {}
},
instanceMethods: {
method3: function() {}
}
}
})
// Example:
var Foo = sequelize.define('foo', { /* attributes */});
Foo.method1()
Foo.method2()
Foo.build().method3()
索引
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}]
}
]
})