#
var User = sequelize.define(
// 默認表名(一般這里寫單數),生成時會自動轉換成復數形式
// 這個值還會作為訪問模型相關的模型時的屬性名,所以建議用小寫形式
'user',
// 字段定義(主鍵、created_at、updated_at默認包含,不用特殊定義)
{
'emp_id': {
'type': Sequelize.CHAR(10), // 字段類型
'allowNull': false, // 是否允許為NULL
'unique': true // 字段是否UNIQUE
},
'nick': {
'type': Sequelize.CHAR(10),
'allowNull': false
},
'department': {
'type': Sequelize.STRING(64),
'allowNull': true
}
}
);
var User = sequelize.define(
'user',
{
'emp_id': {
'type': Sequelize.CHAR(10), // 字段類型
'allowNull': false, // 是否允許為NULL
'unique': true // 字段是否UNIQUE
},
'nick': {
'type': Sequelize.CHAR(10),
'allowNull': false
},
'department': {
'type': Sequelize.STRING(64),
'allowNull': true
}
},
{
// 自定義表名
'freezeTableName': true,
'tableName': 'xyz_users',
// 是否需要增加createdAt、updatedAt、deletedAt字段
'timestamps': true,
// 不需要createdAt字段
'createdAt': false,
// 將updatedAt字段改個名
'updatedAt': 'utime'
// 將deletedAt字段改名
// 同時需要設置paranoid為true(此種模式下,刪除數據時不會進行物理刪除,而是設置deletedAt為當前時間
'deletedAt': 'dtime',
'paranoid': true
}
);
SQL:
CREATE TABLE IF NOT EXISTS `users` (
`id` INTEGER NOT NULL auto_increment ,
`emp_id` CHAR(10) NOT NULL UNIQUE,
`nick` CHAR(10) NOT NULL,
`department` VARCHAR(64),
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
建表SQL會自動執行的意思是主動調用sync的時候。
類似這樣:User.sync({force: true});(加force:true,會先刪掉表后再建表)。
也可以先定義好表結構,再來定義Sequelize模型,這時可以不用sync。
兩者在定義階段沒有什么關系,直到我們真正開始操作模型時,才會觸及到表的操作,
但是我們當然還是要盡量保證模型和表的同步(可以借助一些migration工具)。
自動建表功能有風險,使用需謹慎。
獲取“干凈”的JSON對象可以調用get({'plain': true})。
增
Sequelize:
// 方法1:build后對象只存在於內存中,調用save后才操作db
var user = User.build({
'emp_id': '1',
'nick': '小紅',
'department': '技術部'
});
user = yield user.save();
console.log(user.get({'plain': true}));
// 方法2:直接操作db
var user = yield User.create({
'emp_id': '2',
'nick': '小明',
'department': '技術部'
});
console.log(user.get({'plain': true}));
SQL:
INSERT INTO `users`
(`id`, `emp_id`, `nick`, `department`, `updated_at`, `created_at`)
VALUES
(DEFAULT, '1', '小紅', '技術部', '2015-11-02 14:49:54', '2015-11-02 14:49:54');
改
Sequelize:
// 方法1:操作對象屬性(不會操作db),調用save后操作db
user.nick = '小白';
user = yield user.save();
console.log(user.get({'plain': true}));
// 方法2:直接update操作db
user = yield user.update({
'nick': '小白白'
});
console.log(user.get({'plain': true}));
SQL:
UPDATE `users`
SET `nick` = '小白白', `updated_at` = '2015-11-02 15:00:04'
WHERE `id` = 1;
限制更新屬性的白名單
// 方法1
user.emp_id = '33';
user.nick = '小白';
user = yield user.save({'fields': ['nick']});
// 方法2
user = yield user.update(
{'emp_id': '33', 'nick': '小白'},
{'fields': ['nick']}
});
刪
Sequelize:
yield user.destroy();
SQL:
DELETE FROM `users` WHERE `id` = 1;
查全部
Sequelize:
var users = yield User.findAll();
console.log(users);
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at` FROM `users`;
限制字段
Sequelize:
var users = yield User.findAll({
'attributes': ['emp_id', 'nick']
});
console.log(users);
SQL:
SELECT `emp_id`, `nick` FROM `users`;
字段重命名
Sequelize:
var users = yield User.findAll({
'attributes': [
'emp_id', ['nick', 'user_nick']
]
});
console.log(users);
SQL:
SELECT `emp_id`, `nick` AS `user_nick` FROM `users`;
where子句
基本條件
Sequelize:
var users = yield User.findAll({
'where': {
'id': [1, 2, 3],
'nick': 'a',
'department': null
}
});
console.log(users);
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
`user`.`id` IN (1, 2, 3) AND
`user`.`nick`='a' AND
`user`.`department` IS NULL;
操作符
操作符是對某個字段的進一步約束,可以有多個(對同一個字段的多個操作符會被轉化為AND)。
Sequelize:
var users = yield User.findAll({
'where': {
'id': {
'$eq': 1, // id = 1
'$ne': 2, // id != 2
'$gt': 6, // id > 6
'$gte': 6, // id >= 6
'$lt': 10, // id < 10
'$lte': 10, // id <= 10
'$between': [6, 10], // id BETWEEN 6 AND 10
'$notBetween': [11, 15], // id NOT BETWEEN 11 AND 15
'$in': [1, 2], // id IN (1, 2)
'$notIn': [3, 4] // id NOT IN (3, 4)
},
'nick': {
'$like': '%a%', // nick LIKE '%a%'
'$notLike': '%a' // nick NOT LIKE '%a'
},
'updated_at': {
'$eq': null, // updated_at IS NULL
'$ne': null // created_at IS NOT NULL
}
}
});
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
(
`user`.`id` = 1 AND
`user`.`id` != 2 AND
`user`.`id` > 6 AND
`user`.`id` >= 6 AND
`user`.`id` < 10 AND
`user`.`id` <= 10 AND
`user`.`id` BETWEEN 6 AND 10 AND
`user`.`id` NOT BETWEEN 11 AND 15 AND
`user`.`id` IN (1, 2) AND
`user`.`id` NOT IN (3, 4)
)
AND
(
`user`.`nick` LIKE '%a%' AND
`user`.`nick` NOT LIKE '%a'
)
AND
(
`user`.`updated_at` IS NULL AND
`user`.`updated_at` IS NOT NULL
);
條件
上面說的條件查詢,都是AND查詢,Sequelize同時也支持OR、NOT、甚至多種條件的聯合查詢。
AND條件
Sequelize:
var users = yield User.findAll({
'where': {
'$and': [
{'id': [1, 2]},
{'nick': null}
]
}
});
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
(
`user`.`id` IN (1, 2) AND
`user`.`nick` IS NULL
);
OR條件
Sequelize:
var users = yield User.findAll({
'where': {
'$or': [
{'id': [1, 2]},
{'nick': null}
]
}
});
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
(
`user`.`id` IN (1, 2) OR
`user`.`nick` IS NULL
);
NOT條件
Sequelize:
var users = yield User.findAll({
'where': {
'$not': [
{'id': [1, 2]},
{'nick': null}
]
}
});
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
NOT (
`user`.`id` IN (1, 2) AND
`user`.`nick` IS NULL
);
轉換規則
Sequelize對where配置的轉換規則的偽代碼大概如下:
function translate(where) {
for (k, v of where) {
if (k == 表字段) {
// 先統一轉為操作符形式
if (v == 基本值) { // k: 'xxx'
v = {'$eq': v};
}
if (v == 數組) { // k: [1, 2, 3]
v = {'$in': v};
}
// 操作符轉換
for (opk, opv of v) {
// op將opk轉換對應的SQL表示
=> k + op(opk, opv) + AND;
}
}
// 邏輯操作符處理
if (k == '$and') {
for (item in v) {
=> translate(item) + AND;
}
}
if (k == '$or') {
for (item in v) {
=> translate(item) + OR;
}
}
if (k == '$not') {
NOT +
for (item in v) {
=> translate(item) + AND;
}
}
}
function op(opk, opv) {
switch (opk) {
case $eq => ('=' + opv) || 'IS NULL';
case $ne => ('!=' + opv) || 'IS NOT NULL';
case $gt => '>' + opv;
case $lt => '<' + opv;
case $gte => '>=' + opv;
case $lte => '<=' + opv;
case $between => 'BETWEEN ' + opv[0] + ' AND ' + opv[1];
case $notBetween => 'NOT BETWEEN ' + opv[0] + ' AND ' + opv[1];
case $in => 'IN (' + opv.join(',') + ')';
case $notIn => 'NOT IN (' + opv.join(',') + ')';
case $like => 'LIKE ' + opv;
case $notLike => 'NOT LIKE ' + opv;
}
}
}
一個復雜例子,基本上就是按上述流程來進行轉換。
Sequelize:
var users = yield User.findAll({
'where': {
'id': [3, 4],
'$not': [
{
'id': {
'$in': [1, 2]
}
},
{
'$or': [
{'id': [1, 2]},
{'nick': null}
]
}
],
'$and': [
{'id': [1, 2]},
{'nick': null}
],
'$or': [
{'id': [1, 2]},
{'nick': null}
]
}
});
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE
`user`.`id` IN (3, 4)
AND
NOT
(
`user`.`id` IN (1, 2)
AND
(`user`.`id` IN (1, 2) OR `user`.`nick` IS NULL)
)
AND
(
`user`.`id` IN (1, 2) AND `user`.`nick` IS NULL
)
AND
(
`user`.`id` IN (1, 2) OR `user`.`nick` IS NULL
);
排序
Sequelize:
var users = yield User.findAll({
'order': [
['id', 'DESC'],
['nick']
]
});
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
ORDER BY `user`.`id` DESC, `user`.`nick`;
分頁
Sequelize:
var countPerPage = 20, currentPage = 5;
var users = yield User.findAll({
'limit': countPerPage, // 每頁多少條
'offset': countPerPage * (currentPage - 1) // 跳過多少條
});
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
LIMIT 80, 20;
查詢一條數據
Sequelize:
user = yield User.findById(1);
user = yield User.findOne({
'where': {'nick': 'a'}
});
SQL:
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE `user`.`id` = 1 LIMIT 1;
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
WHERE `user`.`nick` = 'a' LIMIT 1;
查詢並獲取數量
Sequelize:
var result = yield User.findAndCountAll({
'limit': 20,
'offset': 0
});
console.log(result);//result.count是數據總數,result.rows是符合查詢條件的所有數據
SQL:
SELECT count(*) AS `count` FROM `users` AS `user`;
SELECT `id`, `emp_id`, `nick`, `department`, `created_at`, `updated_at`
FROM `users` AS `user`
LIMIT 20;
批量操作
插入
Sequelize:
var users = yield User.bulkCreate(
[
{'emp_id': 'a', 'nick': 'a'},
{'emp_id': 'b', 'nick': 'b'},
{'emp_id': 'c', 'nick': 'c'}
]
);
SQL:
INSERT INTO `users`
(`id`,`emp_id`,`nick`,`created_at`,`updated_at`)
VALUES
(NULL,'a','a','2015-11-03 02:43:30','2015-11-03 02:43:30'),
(NULL,'b','b','2015-11-03 02:43:30','2015-11-03 02:43:30'),
(NULL,'c','c','2015-11-03 02:43:30','2015-11-03 02:43:30');
這里需要注意,返回的users數組里面每個對象的id值會是null。
如果需要id值,可以重新取下數據。
更新
Sequelize:
var affectedRows = yield User.update(
{'nick': 'hhhh'},
{
'where': {
'id': [2, 3, 4]
}
}
);
SQL:
UPDATE `users`
SET `nick`='hhhh',`updated_at`='2015-11-03 02:51:05'
WHERE `id` IN (2, 3, 4);
這里返回的affectedRows其實是一個數組,里面只有一個元素,表示更新的數據條數
刪除
Sequelize:
var affectedRows = yield User.destroy({
'where': {'id': [2, 3, 4]}
});
SQL:
DELETE FROM `users` WHERE `id` IN (2, 3, 4);
這里返回的affectedRows是一個數字,表示刪除的數據條數。
關系
一對一
模型定義
Sequelize:
var User = sequelize.define('user',
{
'emp_id': {
'type': Sequelize.CHAR(10),
'allowNull': false,
'unique': true
}
}
);
var Account = sequelize.define('account',
{
'email': {
'type': Sequelize.CHAR(20),
'allowNull': false
}
}
);
/*
* User的實例對象將擁有getAccount、setAccount、addAccount方法
*/
User.hasOne(Account);
/*
* Account的實例對象將擁有getUser、setUser、addUser方法
*/
Account.belongsTo(User);
SQL:
CREATE TABLE IF NOT EXISTS `users` (
`id` INTEGER NOT NULL auto_increment ,
`emp_id` CHAR(10) NOT NULL UNIQUE,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `accounts` (
`id` INTEGER NOT NULL auto_increment ,
`email` CHAR(20) NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
`user_id` INTEGER,
PRIMARY KEY (`id`),
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB;
可以看到,這種關系中外鍵user_id加在了Account上。
另外,Sequelize還生成了外鍵約束。
一般來說,外鍵約束在有些自己定制的數據庫系統里面是禁止的,因為會帶來一些性能問題。
所以,建表的SQL一般就去掉約束,同時給外鍵加一個索引(加速查詢),
數據的一致性就靠應用層來保證了。
增
Sequelize:
var user = yield User.create({'emp_id': '1'});
var account = user.createAccount({'email': 'a'});
console.log(account.get({'plain': true}));
SQL:
INSERT INTO `users`
(`id`,`emp_id`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'1','2015-11-03 06:24:53','2015-11-03 06:24:53');
INSERT INTO `accounts`
(`id`,`email`,`user_id`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'a',1,'2015-11-03 06:24:53','2015-11-03 06:24:53');
SQL執行邏輯是:
使用對應的的user_id作為外鍵在accounts表里插入一條數據。
改
Sequelize:
var anotherAccount = yield Account.create({'email': 'b'});
console.log(anotherAccount);
anotherAccount = yield user.setAccount(anotherAccount);
console.log(anotherAccount);
SQL:
INSERT INTO `accounts`
(`id`,`email`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'b','2015-11-03 06:37:14','2015-11-03 06:37:14');
SELECT `id`, `email`, `created_at`, `updated_at`, `user_id`
FROM `accounts` AS `account` WHERE (`account`.`user_id` = 1);
UPDATE `accounts` SET `user_id`=NULL,`updated_at`='2015-11-03 06:37:14' WHERE `id` = 1;
UPDATE `accounts` SET `user_id`=1,`updated_at`='2015-11-03 06:37:14' WHERE `id` = 2;
SQL執行邏輯是:
插入一條account數據,此時外鍵user_id是空的,還沒有關聯user
找出當前user所關聯的account並將其user_id置為`NUL(為了保證一對一關系)
設置新的acount的外鍵user_id為user的屬性id,生成關系
刪
Sequelize:
yield user.setAccount(null);
SQL:
SELECT `id`, `email`, `created_at`, `updated_at`, `user_id`
FROM `accounts` AS `account`
WHERE (`account`.`user_id` = 1);
UPDATE `accounts`
SET `user_id`=NULL,`updated_at`='2015-11-04 00:11:35'
WHERE `id` = 1;
這里的刪除實際上只是“切斷”關系,並不會真正的物理刪除記錄。
SQL執行邏輯是:
找出user所關聯的account數據
將其外鍵user_id設置為NULL,完成關系的“切斷”
查
情況1
查詢user的所有滿足條件的note數據。
Sequelize:
var notes = yield user.getNotes({
'where': {
'title': {
'$like': '%css%'
}
}
});
notes.forEach(function(note) {
console.log(note);
});
SQL:
SELECT `id`, `title`, `created_at`, `updated_at`, `user_id`
FROM `notes` AS `note`
WHERE (`note`.`user_id` = 1 AND `note`.`title` LIKE '%a%');
這種方法的SQL很簡單,直接根據user的id值來查詢滿足條件的note即可。
情況2
查詢所有滿足條件的note,同時獲取note屬於哪個user。
Sequelize:
var notes = yield Note.findAll({
'include': [User],
'where': {
'title': {
'$like': '%css%'
}
}
});
notes.forEach(function(note) {
// note屬於哪個user可以通過note.user訪問
console.log(note);
});
SQL:
SELECT `note`.`id`, `note`.`title`, `note`.`created_at`, `note`.`updated_at`, `note`.`user_id`,
`user`.`id` AS `user.id`, `user`.`emp_id` AS `user.emp_id`, `user`.`created_at` AS `user.created_at`, `user`.`updated_at` AS `user.updated_at`
FROM `notes` AS `note` LEFT OUTER JOIN `users` AS `user`
ON `note`.`user_id` = `user`.`id`
WHERE `note`.`title` LIKE '%css%';
這種方法,因為獲取的主體是note,所以將notes去left join了users。
情況3
查詢所有滿足條件的user,同時獲取該user所有滿足條件的note。
Sequelize:
var users = yield User.findAll({
'include': [Note],
'where': {
'created_at': {
'$lt': new Date()
}
}
});
users.forEach(function(user) {
// user的notes可以通過user.notes訪問
console.log(user);
});
SQL:
SELECT `user`.`id`, `user`.`emp_id`, `user`.`created_at`, `user`.`updated_at`,
`notes`.`id` AS `notes.id`, `notes`.`title` AS `notes.title`, `notes`.`created_at` AS `notes.created_at`, `notes`.`updated_at` AS `notes.updated_at`, `notes`.`user_id` AS `notes.user_id`
FROM `users` AS `user` LEFT OUTER JOIN `notes` AS `notes`
ON `user`.`id` = `notes`.`user_id`
WHERE `user`.`created_at` < '2015-11-05 01:51:35';
這種方法獲取的主體是user,所以將users去left join了notes。
關於eager loading。
include里面傳遞的是去取相關模型,默認是取全部,也可以再對這個模型進行一層過濾。
Sequelize:
// 查詢創建時間在今天之前的所有user,同時獲取他們note的標題中含有關鍵字css的所有note
var users = yield User.findAll({
'include': [
{
'model': Note,
'where': {
'title': {
'$like': '%css%'
}
}
}
],
'where': {
'created_at': {
'$lt': new Date()
}
}
});
SQL:
SELECT `user`.`id`, `user`.`emp_id`, `user`.`created_at`, `user`.`updated_at`,
`notes`.`id` AS `notes.id`, `notes`.`title` AS `notes.title`, `notes`.`created_at` AS `notes.created_at`, `notes`.`updated_at` AS `notes.updated_at`, `notes`.`user_id` AS `notes.user_id`
FROM `users` AS `user` INNER JOIN `notes` AS `notes`
ON `user`.`id` = `notes`.`user_id` AND `notes`.`title` LIKE '%css%'
WHERE `user`.`created_at` < '2015-11-05 01:58:31';
注意:當對include的模型加了where過濾時,會使用inner join來進行查詢,
這樣保證只有那些擁有標題含有css關鍵詞note的用戶才會返回。
多對多關系
模型定義
Sequelize:
var Note = sequelize.define('note',
{
'title': {
'type': Sequelize.CHAR(64),
'allowNull': false
}
}
);
var Tag = sequelize.define('tag',
{
'name': {
'type': Sequelize.CHAR(64),
'allowNull': false,
'unique': true
}
}
);
var Tagging = sequelize.define('tagging',
{
'type': {
'type': Sequelize.INTEGER(),
'allowNull': false
}
}
);
// Note的實例擁有getTags、setTags、addTag、addTags、createTag、removeTag、hasTag方法
Note.belongsToMany(Tag, {'through': Tagging});
// Tag的實例擁有getNotes、setNotes、addNote、addNotes、createNote、removeNote、hasNote方法
Tag.belongsToMany(Note, {'through': Tagging});
SQL:
CREATE TABLE IF NOT EXISTS `notes` (
`id` INTEGER NOT NULL auto_increment ,
`title` CHAR(64) NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `tags` (
`id` INTEGER NOT NULL auto_increment ,
`name` CHAR(64) NOT NULL UNIQUE,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `taggings` (
`type` INTEGER NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
`tag_id` INTEGER ,
`note_id` INTEGER ,
PRIMARY KEY (`tag_id`, `note_id`),
FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`note_id`) REFERENCES `notes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
多對多關系中單獨生成了一張關系表,並設置了2個外鍵tag_id和note_id來和tags和notes進行關聯。
增
方法1
Sequelize:
var note = yield Note.create({'title': 'note'});
yield note.createTag({'name': 'tag'}, {'type': 0});
SQL:
INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'note','2015-11-06 02:14:38','2015-11-06 02:14:38');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag','2015-11-06 02:14:38','2015-11-06 02:14:38');
INSERT INTO `taggings`
(`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(1,1,0,'2015-11-06 02:14:38','2015-11-06 02:14:38');
SQL執行邏輯:
在notes表插入記錄
在tags表中插入記錄
使用對應的值設置外鍵tag_id和note_id以及關系模型本身需要的屬性(type: 0)在關系表tagging中插入記錄
關系表本身需要的屬性,通過傳遞一個額外的對象給設置方法來實現。
方法2
Sequelize:
var note = yield Note.create({'title': 'note'});
var tag = yield Tag.create({'name': 'tag'});
yield note.addTag(tag, {'type': 1});
SQL:
INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'note','2015-11-06 02:20:52','2015-11-06 02:20:52');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag','2015-11-06 02:20:52','2015-11-06 02:20:52');
INSERT INTO `taggings`
(`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(1,1,1,'2015-11-06 02:20:52','2015-11-06 02:20:52');
這種方法和上面的方法實際上是一樣的。只是先手動create了一個Tag模型。
方法3
Sequelize:
var note = yield Note.create({'title': 'note'});
var tag1 = yield Tag.create({'name': 'tag1'});
var tag2 = yield Tag.create({'name': 'tag2'});
yield note.addTags([tag1, tag2], {'type': 2});
SQL:
INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'note','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag1','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag2','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `taggings` (`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(1,1,2,'2015-11-06 02:25:18','2015-11-06 02:25:18'),
(2,1,2,'2015-11-06 02:25:18','2015-11-06 02:25:18');
這種方法可以進行批量添加。當執行addTags時,實際上就是設置好對應的外鍵及關系模型本身的屬性,然后在關系表中批量的插入數據。
改
Sequelize:
// 先添加幾個tag
var note = yield Note.create({'title': 'note'});
var tag1 = yield Tag.create({'name': 'tag1'});
var tag2 = yield Tag.create({'name': 'tag2'});
yield note.addTags([tag1, tag2], {'type': 2});
// 將tag改掉
var tag3 = yield Tag.create({'name': 'tag3'});
var tag4 = yield Tag.create({'name': 'tag4'});
yield note.setTags([tag3, tag4], {'type': 3});
SQL:
/* 前面添加部分的sql,和上面一樣*/
INSERT INTO `notes`
(`id`,`title`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'note','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag1','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag2','2015-11-06 02:25:18','2015-11-06 02:25:18');
INSERT INTO `taggings`
(`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(1,1,2,'2015-11-06 02:25:18','2015-11-06 02:25:18'),
(2,1,2,'2015-11-06 02:25:18','2015-11-06 02:25:18');
/* 更改部分的sql */
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag3','2015-11-06 02:29:55','2015-11-06 02:29:55');
INSERT INTO `tags`
(`id`,`name`,`updated_at`,`created_at`)
VALUES
(DEFAULT,'tag4','2015-11-06 02:29:55','2015-11-06 02:29:55');
/* 先刪除關系 */
DELETE FROM `taggings`
WHERE `note_id` = 1 AND `tag_id` IN (1, 2);
/* 插入新關系 */
INSERT INTO `taggings`
(`tag_id`,`note_id`,`type`,`created_at`,`updated_at`)
VALUES
(3,1,3,'2015-11-06 02:29:55','2015-11-06 02:29:55'),
(4,1,3,'2015-11-06 02:29:55','2015-11-06 02:29:55');
執行邏輯是,先將tag1、tag2在關系表中的關系刪除,然后再將tag3、tag4對應的關系插入關系表。
刪
Sequelize:
// 先添加幾個tag
var note = yield Note.create({'title': 'note'});
var tag1 = yield Tag.create({'name': 'tag1'});
var tag2 = yield Tag.create({'name': 'tag2'});
var tag3 = yield Tag.create({'name': 'tag2'});
yield note.addTags([tag1, tag2, tag3], {'type': 2});
// 刪除一個
yield note.removeTag(tag1);
// 全部刪除
yield note.setTags([]);
SQL:
/* 刪除一個 */
DELETE FROM `taggings` WHERE `note_id` = 1 AND `tag_id` IN (1);
/* 刪除全部 */
SELECT `type`, `created_at`, `updated_at`, `tag_id`, `note_id`
FROM `taggings` AS `tagging`
WHERE `tagging`.`note_id` = 1;
DELETE FROM `taggings` WHERE `note_id` = 1 AND `tag_id` IN (2, 3);
刪除一個很簡單,直接將關系表中的數據刪除。
全部刪除時,首先需要查出關系表中note_id對應的所有數據,然后一次刪掉。
查
情況1
查詢note所有滿足條件的tag。
Sequelize:
var tags = yield note.getTags({
//這里可以對tags進行where
});
tags.forEach(function(tag) {
// 關系模型可以通過tag.tagging來訪問
console.log(tag);
});
SQL:
SELECT `tag`.`id`, `tag`.`name`, `tag`.`created_at`, `tag`.`updated_at`,
`tagging`.`type` AS `tagging.type`, `tagging`.`created_at` AS `tagging.created_at`, `tagging`.`updated_at` AS `tagging.updated_at`, `tagging`.`tag_id` AS `tagging.tag_id`, `tagging`.`note_id` AS `tagging.note_id`
FROM `tags` AS `tag`
INNER JOIN `taggings` AS `tagging`
ON
`tag`.`id` = `tagging`.`tag_id` AND `tagging`.`note_id` = 1;
可以看到這種查詢,就是執行一個inner join。
情況2
查詢所有滿足條件的tag,同時獲取每個tag所在的note。
Sequelize:
var tags = yield Tag.findAll({
'include': [
{
'model': Note
// 這里可以對notes進行where
}
]
// 這里可以對tags進行where
});
tags.forEach(function(tag) {
// tag的notes可以通過tag.notes訪問,關系模型可以通過tag.notes[0].tagging訪問
console.log(tag);
});
SQL:
SELECT `tag`.`id`, `tag`.`name`, `tag`.`created_at`, `tag`.`updated_at`,
`notes`.`id` AS `notes.id`, `notes`.`title` AS `notes.title`, `notes`.`created_at` AS `notes.created_at`, `notes`.`updated_at` AS `notes.updated_at`,
`notes.tagging`.`type` AS `notes.tagging.type`, `notes.tagging`.`created_at` AS `notes.tagging.created_at`, `notes.tagging`.`updated_at` AS `notes.tagging.updated_at`, `notes.tagging`.`tag_id` AS `notes.tagging.tag_id`, `notes.tagging`.`note_id` AS `notes.tagging.note_id`
FROM `tags` AS `tag`
LEFT OUTER JOIN
(
`taggings` AS `notes.tagging` INNER JOIN `notes` AS `notes`
ON
`notes`.`id` = `notes.tagging`.`note_id`
)
ON `tag`.`id` = `notes.tagging`.`tag_id`;
首先是notes和taggings進行了一個inner join,選出notes;
然后tags和剛join出的集合再做一次left join,得到結果。
情況3
查詢所有滿足條件的note,同時獲取每個note所有滿足條件的tag。
Sequelize:
var notes = yield Note.findAll({
'include': [
{
'model': Tag
// 這里可以對tags進行where
}
]
// 這里可以對notes進行where
});
notes.forEach(function(note) {
// note的tags可以通過note.tags訪問,關系模型通過note.tags[0].tagging訪問
console.log(note);
});
SQL:
SELECT
`note`.`id`, `note`.`title`, `note`.`created_at`, `note`.`updated_at`,
`tags`.`id` AS `tags.id`, `tags`.`name` AS `tags.name`, `tags`.`created_at` AS `tags.created_at`, `tags`.`updated_at` AS `tags.updated_at`,
`tags.tagging`.`type` AS `tags.tagging.type`, `tags.tagging`.`created_at` AS `tags.tagging.created_at`, `tags.tagging`.`updated_at` AS `tags.tagging.updated_at`, `tags.tagging`.`tag_id` AS `tags.tagging.tag_id`, `tags.tagging`.`note_id` AS `tags.tagging.note_id`
FROM `notes` AS `note`
LEFT OUTER JOIN
(
`taggings` AS `tags.tagging` INNER JOIN `tags` AS `tags`
ON
`tags`.`id` = `tags.tagging`.`tag_id`
)
ON
`note`.`id` = `tags.tagging`.`note_id`;
這個查詢和上面的查詢類似。
首先是tags和taggins進行了一個inner join,選出tags;
然后notes和剛join出的集合再做一次left join,得到結果。
