참고자료
https://github.com/sequelize/sequelize/issues/10857
https://github.com/sequelize/sequelize/issues/10857#issuecomment-534351978
목표
db의 column은 모두 snake_case로,
대신 JS에서 해당 컬럼을 다룰 때에는 camelCase로 다루기.
이유는 프론트 단과의 통신 과정에서 case 충돌을 막기 위함이다.
예를 들어 res.data.profile_image VS. res.data.profileImage를 고민한다면
일반적으로 프론트 단에서는 후자를 쓰는 것이 자연스럽다.
백에서는 data를 넘겨줄 때 camelCase로 넘겨주면 편할 것이다.
db에서 값을 가져올 때 column명 그대로 snake_case 상태로 가져온다면, camelCase로 변환하는 불편한 과정을 거쳐야할 수도 있다. 또는 그대로 snake_case를 넘겨주었을 때 프론트와의 통신에서 의도치 않은 불편함을 유발할 수 있다.
1. 기본 설정 방법
sequelize의 model 과정에서 간단한 설정이 필요하다.
camelCase로 컬럼을 작성하되, field 옵션으로 snake_case로 작명된 column을 가리키면 된다.
다음은 예시 코드이다.
import { Sequelize, DataTypes } from 'sequelize';
class User extends Sequelize.Model {
static init(sequelize) {
return super.init(
{
userId: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
field: 'user_id',
}
},
{
intialAutoIncrement: 1,
sequelize,
},
)
}
}
export { User };
2. timestamp 자동 생성
timestamps로 created_at, updated_at 컬럼을 자동으로 생성하고 다룰 수도 있다.
import { Sequelize, DataTypes } from 'sequelize';
class User extends Sequelize.Model {
static init(sequelize) {
return super.init(
{
userId: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
field: 'user_id',
},
},
{
intialAutoIncrement: 1,
sequelize,
tableName: 'Users',
modelName: 'User',
timestamps: true, // 1. timestamps 자동 생성 기능 설정
underscored: true, // 2. underscored 옵션을 설정
}
);
}
}
export { User };
underscored 옵션은 JS에서 camelCased된 변수와 db단에서 snake_cased인 column을 자동으로 연결해준다.
만약 underscored 설정을 하지 않으면 camelCase 형태로 컬럼에 접근하게 된다. ( createdAt, updatedAt )
따라서 첫 설정 시 이 옵션을 사용하지 않았다면 db에도 createdAt, updatedAt이 형성되었을 것이며,
snake_case로 설정하여 table을 생성했다 해도, 해당 컬럼에 접근할 수 없을 것이다.
const attributes = { exclude: ['userId', 'password', 'status', 'createdAt', 'updatedAt'] };
const user = await this.User.findOne({
where: { userId },
attributes,
});
실제 프로젝트에서 사용 중인 service 코드이다.
exclude 옵션은 지정한 column을 제외한 모든 컬럼을 select하는 기능이다.
camelCase로 설정하였으나 접근할때에는 snake_cased된 column을 배제하여 아래와 같은 결과값을 가져온다. (postman)
3. foreignkey 설정
sequelize.associate 기능을 활용하여 table 간의 부모 자식 관계를 설정할 수 있다.
이 때 foreignkey 역시 camelCase로 통신할 수 있도록 설정할 수 있다.
import { Sequelize, DataTypes } from 'sequelize';
class Favor extends Sequelize.Model {
static init(sequelize) {
return super.init(
{
favorId: {
field: 'favor_id',
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
movie: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
},
{
intialAutoIncrement: 1,
sequelize,
timestamps: true,
charset: 'utf8', // 한국어 설정
collate: 'utf8_general_ci', // 한국어 설정
tableName: 'Favors',
modelName: 'Favor',
underscored: true,
}
);
}
static associate(db) {
db.Favor.belongsTo(db.User, {
foreignKey: {
name: 'userId',
field: 'user_id',
},
sourceKey: 'userId',
});
}
}
export { Favor };
associate 함수에서 User 테이블에 있는 user_id column을 가져와 Favor table에도 만드려고 한다.
sourceKey는 Favor table의 입장에서 User table을 접근할 때의 연결고리이며
foreignKey는 sourceKey로 연동된 User table에서 user_id column에 접근한 후(field 옵션), 그 값을 Favor table에 userId라는 이름으로 설정(name 옵션)하는 것이다.
이제 userId를 가지고 User table 뿐만 아니라 Favor table에도 접근할 수 있게 된다.
프로젝트에서 활용한 사례 코드를 첨부하며 글을 마무리한다!
async addUser(email) {
const newUser = await this.User.create({ email });
const { userId } = newUser.dataValues;
await this.Favor.create({ userId });
}
'Database' 카테고리의 다른 글
[DB] Connection pool의 실용성과 유의점 (0) | 2022.09.20 |
---|---|
[Mongo] find / limit query의 중요성 (feat. Array.slice()) (0) | 2022.07.02 |
[Mongo] 검색 엔진 없이 효과적으로 검색해보기 (Feat. $text, $search, $regex, aggregate) (0) | 2022.06.28 |