JOINについて調べてみました。DBはMySQLです。
結果はrequired: false
を設定するとLEFT OUTER JOIN、 required: true
を設定するとINNER JOINになりました。
データ
この様なデータをDBに入れてLEFT OUTER JOINとINNER JOINの挙動を確認してみます。
has_books_userというユーザーにはbookのレコードが二つ紐付いており、has_not_book_userはbookのレコードが紐付いていません。
Userテーブル
id | name | createdAt | updatedAt |
---|---|---|---|
1 | has_books_user | 2018-03-23 15:18:49 | 2018-03-23 15:18:49 |
2 | has_not_book_user | 2018-03-23 15:18:49 | 2018-03-23 15:18:49 |
Bookテーブル
id | name | userId | createdAt | updatedAt |
---|---|---|---|---|
1 | エベレストを越えて | 1 | 2018-03-28 04:46:27 | 2018-03-28 04:46:27 |
2 | 青春を山に賭けて | 1 | 2018-03-28 04:46:27 | 2018-03-28 04:46:27 |
アソシエーションの設定
事前にhasMany(hasOne)やbelongsToの設定をしておきます。
userモデル
'use strict';
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
name: DataTypes.STRING
}, {});
User.associate = function(models) {
User.hasMany(models.Book, {foreignKey: 'userId'});
};
return User;
};
bookモデル
'use strict';
module.exports = (sequelize, DataTypes) => {
var Book = sequelize.define('Book', {
name: DataTypes.STRING,
userId: DataTypes.INTEGER
}, {});
Book.associate = function(models) {
Book.belongsTo(models.User);
};
return Book;
};
LEFT OUTER JOIN
db.User.findAll({
where: {
id: [1,2]
},
raw: true,
include: [{
model: db.Book,
required: false
}]
}).then((users)=>{
console.log(users);
})
SQL
SELECT `User`.`id`, `User`.`name`, `User`.`createdAt`, `User`.`updatedAt`, `Books`.`id` AS `Books.id`, `Books`.`name` AS `Books.name`, `Books`.`userId` AS `Books.userId`, `Books`.`createdAt` AS `Books.createdAt`, `Books`.`updatedAt` AS `Books.updatedAt`, `Books`.`UserId` AS `Books.UserId`
FROM `Users` AS `User`
LEFT OUTER JOIN `Books` AS `Books` ON `User`.`id` = `Books`.`userId`
WHERE `User`.`id` IN (1, 2);
結果
LEFT OUTER JOINの為、bookのレコードを持っていないuserも出力されています。
[ { id: 1,
name: 'has_books_user',
createdAt: 2018-03-23T15:18:49.000Z,
updatedAt: 2018-03-23T15:18:49.000Z,
'Books.id': 1,
'Books.name': 'エベレストを越えて',
'Books.userId': 1,
'Books.createdAt': 2018-03-28T04:46:27.000Z,
'Books.updatedAt': 2018-03-28T04:46:27.000Z,
'Books.UserId': 1 },
{ id: 1,
name: 'has_books_user',
createdAt: 2018-03-23T15:18:49.000Z,
updatedAt: 2018-03-23T15:18:49.000Z,
'Books.id': 2,
'Books.name': '青春を山に賭けて',
'Books.userId': 1,
'Books.createdAt': 2018-03-28T04:46:27.000Z,
'Books.updatedAt': 2018-03-28T04:46:27.000Z,
'Books.UserId': 1 },
{ id: 2,
name: 'has_not_book_user',
createdAt: 2018-03-23T15:18:49.000Z,
updatedAt: 2018-03-23T15:18:49.000Z,
'Books.id': null,
'Books.name': null,
'Books.userId': null,
'Books.createdAt': null,
'Books.updatedAt': null,
'Books.UserId': null } ]
INNER JOIN
db.User.findAll({
where: {
id: [1,2]
},
raw: true,
include: [{
model: db.Book,
required: true
}]
}).then((users)=>{
console.log(users);
})
SQL
SELECT `User`.`id`, `User`.`name`, `User`.`createdAt`, `User`.`updatedAt`, `Books`.`id` AS `Books.id`, `Books`.`name` AS `Books.name`, `Books`.`userId` AS `Books.userId`, `Books`.`createdAt` AS `Books.createdAt`, `Books`.`updatedAt` AS `Books.updatedAt`, `Books`.`UserId` AS `Books.UserId`
FROM `Users` AS `User`
INNER JOIN `Books` AS `Books` ON `User`.`id` = `Books`.`userId`
WHERE `User`.`id` IN (1, 2);
結果
INNER JOINの為、bookのレコードを持っていないuserは出力されていません。
[ { id: 1,
name: 'has_books_user',
createdAt: 2018-03-23T15:18:49.000Z,
updatedAt: 2018-03-23T15:18:49.000Z,
'Books.id': 1,
'Books.name': 'エベレストを越えて',
'Books.userId': 1,
'Books.createdAt': 2018-03-28T04:46:27.000Z,
'Books.updatedAt': 2018-03-28T04:46:27.000Z,
'Books.UserId': 1 },
{ id: 1,
name: 'has_books_user',
createdAt: 2018-03-23T15:18:49.000Z,
updatedAt: 2018-03-23T15:18:49.000Z,
'Books.id': 2,
'Books.name': '青春を山に賭けて',
'Books.userId': 1,
'Books.createdAt': 2018-03-28T04:46:27.000Z,
'Books.updatedAt': 2018-03-28T04:46:27.000Z,
'Books.UserId': 1 } ]