안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
[Sequelize] boolean이 true/false가 아닌 0/1 숫자로 리턴되는 이슈
1️⃣ raw: true 옵션 사용할 경우
예를 들어, 아래와 같은 스키마를 가진 테이블이 있다고 가정해보겠습니다.
import { DataTypes, Model, Sequelize } from "sequelize";
import Post from "./post";
type ProviderType = "local" | "kakao";
class User extends Model {
public readonly id: number;
public email: string;
public nick: string;
public password: string;
public provider: ProviderType;
public sns_id: string;
public is_married: boolean;
static initiate(sequelize: Sequelize) {
User.init(
{
email: {
type: DataTypes.STRING(40),
allowNull: true,
unique: true,
},
nick: {
type: DataTypes.STRING(15),
allowNull: false,
},
password: {
type: DataTypes.STRING(100),
allowNull: true,
},
provider: {
type: DataTypes.ENUM("local", "kakao"),
allowNull: false,
defaultValue: "local",
},
sns_id: {
type: DataTypes.STRING(30),
allowNull: true,
},
is_married: {
type: DataTypes.BOOLEAN(),
allowNull: false,
},
},
{
sequelize,
underscored: true,
timestamps: true,
modelName: "User",
tableName: "users",
paranoid: true, // deleted_at 추가 (soft delete)
charset: "utf8",
collate: "utf8_general_ci",
}
);
}
static associate() {
User.hasMany(Post);
// 팔로워
User.belongsToMany(User, { foreignKey: "following_id", as: "followers", through: "Follow" });
User.belongsToMany(User, { foreignKey: "follower_id", as: "followings", through: "Follow" });
}
}
export default User;
Sequelize를 통해 User 모델과 그에 따른 users 테이블을 생성하였습니다.
이 때, married를 boolean 타입으로 지정했지만, MySQL에는 boolean 타입이 아닌 TINYINT(1) 타입인 것을 확인할 수 있습니다.
데이터베이스에 저장된 값 역시 true | false가 아닌 0 | 1 인 것을 확인할 수 있습니다.
⭐️ 데이터 조회 시 raw: true
옵션 적용하지 않았을 때 리턴 값
router.get("/users", async (req: Request, res: Response, next: NextFunction) => {
try {
const user = await User.findOne({
where: {
id: 1,
},
});
res.status(200).json(user);
} catch (error) {
console.error(error);
}
});
// POSTMAN 리턴 값
{
"id": 1,
"email": "abc@test.com",
"nick": "chany",
"password": "1234",
"provider": "local",
"sns_id": null,
"is_married": true,
"createdAt": "2023-07-28T07:13:37.000Z",
"updatedAt": "2023-07-28T07:13:37.000Z",
"deletedAt": null
}
is_married가 true로 잘 리턴되는 것을 확인할 수 있습니다.
⭐️ 데이터 조회 시 raw: true
옵션 적용했을 때 리턴 값
router.get("/users", async (req: Request, res: Response, next: NextFunction) => {
try {
const user = await User.findOne({
where: {
id: 1,
},
raw: true
});
res.status(200).json(user);
} catch (error) {
console.error(error);
}
});
// POSTMAN 리턴 값
{
"id": 1,
"email": "abc@test.com",
"nick": "chany",
"password": "1234",
"provider": "local",
"sns_id": null,
"is_married": 1,
"createdAt": "2023-07-28T07:13:37.000Z",
"updatedAt": "2023-07-28T07:13:37.000Z",
"deletedAt": null
}
is_married가 true | false가 아닌 1로 리턴되는 것을 확인할 수 있습니다.
2️⃣ SubQuery에서 boolean 값을 리턴할 경우 (ex. IF...)
const user = await User.findOne({
attributes: [[Sequelize.literal("IF(provider = 'kakao', true, false)"), "is_kakao_login"]],
});
// POSTMAN 리턴 값
{
"is_kakao_login": 0
}
역시 true | false가 아닌 0 | 1로 리턴 되는 것을 확인할 수 있습니다.
SubQuery에서 true | false를 문자열 'true' 혹은 'false'로 리턴하면 true, false로 리턴할 수 있지만,
프론트 단에서는 해당 값이 boolean이 아닌 문자열이므로, 분기 처리가 까다로울 수 있습니다.
해결책
1️⃣ raw: true
옵션을 제거
2️⃣ json으로 CAST
const user = await User.findOne({
attributes: [
[
Sequelize.literal("IF(provider = 'kakao', CAST(true as json), CAST(false as json))"),
"is_kakao_login",
],
],
});
// POSTMAN 리턴 값
{
"is_kakao_login": false
}
boolean true | false로 리턴 되는 것을 확인할 수 있습니다.
✅ 참고 사이트
https://bugs.mysql.com/bug.php?id=79813