http://sequelizejs.com/articles/getting-started
本文主要介绍Sequelize的一些基础概念,并将学习一些关于数据库设置,数据访问常用场景的编写方式。
我们将跳过一些基础内容,直接开始介绍Sequelize的一些内容。在我们开始之前,需要做如下准备:
Node.js V0.8 以上版本
一个数据库/SQLite
数据库的使用授权
了解数据库的运行方式
可以选择准备一杯咖啡 :)
如果你的电脑和咖啡都准备好了,我们就可以开始启动了。
第一步:我需要建立一个目录,并通过NPM将其初始化。
mkdir my-project cd my-projectnpm init
NPM会询问一些问题,可以直接回车直到结束。接下来,可以开始安装Sequelize,以及所选择的数据库连接组件库。
npm install --save sequelize npm install --save pg # for postgres npm install --save mysql # for mysql npm install --save sqlite3 # for sqlite npm install --save mariasql # for mariasql
打开你所喜欢的文本编辑器,建立一个名为app.js文件,添加一下内容:
var Sequelize = require('sequelize') , sequelize = new Sequelize('database_name', 'username', 'password', { dialect: "mysql", // or 'sqlite', 'postgres', 'mariadb' port: 3306, // or 5432 (for postgres) }) sequelize .authenticate() .complete(function(err) { if (!!err) { console.log('Unable to connect to the database:', err) } else { console.log('Connection has been established successfully.') } })
Sequelize支持两种Schema的管理方式,你可以通过一种被称为migrations的程序化的方式改变数据库的结构,或者使用Sequelize来为你创建数据库表。
如果你需要将应用部署至众多不同的服务器环境,migrations方式会是你的必选,虽然它会在配置过程中耗掉大量的时间。
以上究其原因,migrations会根据Schema当前的状态来保持你数据库的一致性。
然而,使用Sequelize的sequelize.sync功能的自动化方式更适用用于你的本机或快速构建原型。
在数据库中创建一个Schema,首先得描述需要创建的数据类型,可以使用sequelize.define,如下:
var User = sequelize.define('User', { username: Sequelize.STRING, password: Sequelize.STRING })
这将在user模型中定义username,password两列属性,此外,Sequelize还会自动添加id,createdAt,updatedAt三列属性。
我们需要在数据库中存储数据,那我们就需要在数据库中建立模型对应的表。
sequelize .sync({ force: true }) .complete(function(err) { if (!!err) { console.log('An error occurred while creating the table:', err) } else { console.log('It worked!') } })
执行后,数据库中user表会加入以下数据列:
id - INT(11)
username - VARCHAR(255)
password - VARCHAR(255)
createdAt - DATETIME
updatedAt - DATETIME
需要注意的是,
{ force: true }
将会删除所有表后,之后再进行重建。
你可能也不需要以上timestamps数据列,或者并不希望模型的名称与数据表的名称一致,那我们这样设置:
var User = sequelize.define('User', { username: Sequelize.STRING, password: Sequelize.STRING }, { tableName: 'my_user_table', // this will define the table's name timestamps: false // this will deactivate the timestamp columns })
如果希望自行定义timestamps的名称,可以做下面的设置:
var User = sequelize.define('User', { username: Sequelize.STRING, password: Sequelize.STRING }, { tableName: 'my_user_table', // this will define the table's name timestamps: false // this will deactivate the timestamp columns })
Sequelize允许两种创建实例的方式,你可以先build一个对象,然后在save;或者直接create进入数据库。
var user = User.build({ username: 'john-doe', password: generatePasswordHash('i-am-so-great') }) user .save() .complete(function(err) { if (!!err) { console.log('The instance has not been saved:', err) } else { console.log('We have a persisted instance now') } })
以上存储一个实例需要使用两步,如果你希望一次完成,可以按照下面方式操作:
User .create({ username: 'john-doe', password: generatePasswordHash('i-am-so-great') }) .complete(function(err, user) { /* ... */ })
每个定义的model都有一些查询方法,用来读取数据内容。查询特定的数据,可以使用Model.find;也可以使用Model.findAll查询多条数据。
User .find({ where: { username: 'john-doe' } }) .complete(function(err, johnDoe) { if (!!err) { console.log('An error occurred while searching for John:', err) } else if (!johnDoe) { console.log('No user with the username "john-doe" has been found.') } else { console.log('Hello ' + johnDoe.username + '!') console.log('All attributes of john:', johnDoe.values) } })
请注意,如果没有找到'john-doe',也不会有错误;
一个常见的用例就是定义两个或多个model之间的联系。声明关联关系后,Sequelize将会知道如何get/set相关联的数据。甚至可以自动创建各自相应的外键数据列。
再看代码之前,我们先了解一下这三种关联关系的一些细节内容。
源对象与目标对象是1对1的关系。一个源对象拥有一个目标对象,一个目标对象从属于一个源对象。
Sequelize认为外键在目标对象映射的数据表中,这就意味着目标对象表中需要有描述外键的列属性。
var Source = sequelize.define('Source', {}) , Target = sequelize.define('Target', {}) Source.hasOne(Target) Target.belongsTo(Source) sequelize .sync({ force: true }) .complete(function(err) { // Even if we didn't define any foreign key or something else, // instances of Target will have a column SourceId! })
一对多关系,一个源对象包含多个目标对象,多个目标对象从属于一个源对象。
Sequelize认为外键在目标对象映射的数据表中,这就意味着目标对象表中需要有描述外键的列属性。
var Source = sequelize.define('Source', {}) , Target = sequelize.define('Target', {}) Source.hasMany(Target) Target.belongsTo(Source) sequelize .sync({ force: true }) .complete(function(err) { // Even if we didn't define any foreign key or something else, // instances of Target will have a column SourceId! })
多对多关系。
Sequelize中期望有中间关联表,用于记录源对象的外键与目标对象的外键。
var Source = sequelize.define('Source', {}) , Target = sequelize.define('Target', {}) Source.hasMany(Target) Target.hasMany(Source) sequelize .sync({ force: true }) .complete(function(err) { // Even if we didn't define any foreign key or something else, // Sequelize will create a table SourcesTargets. })
定义关联很容易,如果不读取或设置这种关联,定义不会有任何作用。
当然models中也会添加入相应的方法,不同的关联关系也会有不同的方法,如下:
var Source = sequelize.define('Source', {}) , Target = sequelize.define('Target', {}) Source.hasOne(Target) Target.belongsTo(Source) Source.create({}).complete(function(err, source) { Target.create({}).complete(function(err, target) { // Set the association source.setTarget(target).complete(function(err) { // Get the association source.getTarget().complete(function(err, _target) { console.log(_target.values) /* { id: 1, createdAt: Sun Dec 08 2013 11:46:42 GMT+0100 (CET), updatedAt: Sun Dec 08 2013 11:46:42 GMT+0100 (CET), SourceId: 1 } */ }) }) }) })
假设我们已经定义的模型(比如前面的代码示例)和同步数据库的Schema,我们可以这样清除关联关系:
source.setTarget(null).complete(function(err) { source.getTarget().complete(function(err, target) { console.log(target) // null }) })
一对多,多对多的关系中,不但要设置关联关系,还需要添加或删除关联关系。
var Source = sequelize.define('Source', {}) , Target = sequelize.define('Target', {}) Source.hasMany(Target) Target.belongsTo(Source) Source.create({}).complete(function(err, source) { Target.create({}).complete(function(err, target1) { Target.create({}).complete(function(err, target2) { // Set the association source.setTargets([target1, target2]).complete(function(err) { // Get the association source.getTargets().complete(function(err, targets) { console.log(targets.length) // = 2 // Remove an association source.removeTarget(target1).complete(function(err) { source.getTargets().complete(function(err, targets) { console.log(targets.length) // = 1 // Check for an association source.hasTarget(target1).complete(function(err, hasTarget) { console.log(hasTarget) // false // Adding an association source.addTarget(target1).complete(function(err) { source.getTargets().complete(function(err, targets) { console.log(targets.length) // = 2 source.hasTarget(target1).complete(function(err, hasTarget) { console.log(hasTarget) // true }) }) }) }) }) }) }) }) }) }) })
现在你已经了解了Sequelize的一些基础知识,你可能希望在一段程序中运用它们。
var Sequelize = require('sequelize') , sequelize = new Sequelize('database_name', 'username', 'password') , User = sequelize.define('User', { username: Sequelize.STRING, password: Sequelize.STRING }) sequelize.sync({ force: true }).complete(function(err) { User.create({ username: 'john', password: '1111' }).complete(function(err, user1) { User.find({ username: 'john' }).complete(function(err, user2) { console.log(user1.values, user2.values) }) }) })
Sequelize的其他高级特新,将在下面章节介绍:
Migrations
Data types
Configuration of the model
Validations
Finders
Associations