daily

23.05.01. Sequelize findOne에서, 테이블 조인과 이름 변경

Juhyuck 2023. 5. 1. 22:58
728x90

Issue

ERD

위 ERD에서, Posts 에서..특정 postId를 가지는 데이터를 조회할 때, 필드로 postId, UserId, title, content, nickname을 찾고 싶다면 어떻게 해야할까?

 

우선 두 테이블을 userId 컬럼이 같은 기준으로 테이블을 조인하고, 각 데이터를 찾으면 될 것 같은데, Sequelize의 findOne 메서드를 사용해서 어떻게 구현해야 하는지가 문제였다.


Try&Error

우선 처음 시도는 테이블 조인부터 해봤다.

 

const post = await Posts.findOne({
            attributes: [
                "postId",
                "UserId",
                "title",
                "content",
                "createdAt",
                "updatedAt",
            ],
            include: [{
                model: Users
            }],
            where: { postId }
        })
        
 // post
 {
  "post": {
    "postId": 2,
    "UserId": 1,
    "title": "게시글 제목입니다.",
    "content": "content 입니다.",
    "createdAt": "2023-05-01T12:49:21.000Z",
    "updatedAt": "2023-05-01T12:49:21.000Z",
    "User": {
      "userId": 1,
      "nickname": "Developer",
      "password": "1234",
      "createdAt": "2023-05-01T12:48:32.000Z",
      "updatedAt": "2023-05-01T12:48:32.000Z"
    }
  }
}

UserId값으로 연결된 Users 테이블의 userId 1의 컬럼이 모두 넘어온다.

 

그럼 include에서 nickname만 atrribute로 정하면?

const post = await Posts.findOne({
            attributes: [
                "postId",
                "UserId",
                "title",
                "content",
                "createdAt",
                "updatedAt",
            ],
            include: [{
                model: Users,
                attributes: ["nickname"]
            }],
            where: { postId }
})

// post
{
  "post": {
    "postId": 2,
    "UserId": 1,
    "title": "게시글 제목입니다.",
    "content": "content 입니다.",
    "createdAt": "2023-05-01T12:49:21.000Z",
    "updatedAt": "2023-05-01T12:49:21.000Z",
    "User": {
      "nickname": "Developer"
    }
  }
}

이제 쓸 수는 있다. 근데, join된 Users 테이블이 User로 한층 더 내려가야 nickname을 얻을 수 있다. 내가 원하는 결과는,

 

// post
{
  "post": {
    "postId": 2,
    "UserId": 1,
    "title": "게시글 제목입니다.",
    "content": "content 입니다.",
    "createdAt": "2023-05-01T12:49:21.000Z",
    "updatedAt": "2023-05-01T12:49:21.000Z",
    "nickname": "Developer"
    }
}

 

이다. 

 

Join한 테이블에서 nickname을 찾으면 될 것 같아서 아래와 같이 바꿔봤더니, parameter가 undefined로 에러가 났다.

        const post = await Posts.findOne({
            attributes: [
                "postId",
                "UserId",
                "title",
                "content",
                "createdAt",
                "updatedAt",                
                "nickname"
            ],
            include: [{
                model: Users
            }],
            where: { postId }
        })

Sequelize가 바꾼 query문을 살펴보면, 그 이유를 알 수 있는데,

"SELECT `Posts`.`postId`, `Posts`.`UserId`, `Posts`.`title`, 
`Posts`.`content`, `Posts`.`createdAt`, `Posts`.`updatedAt`, `Posts`.`nickname` 
FROM `Posts` AS `Posts` LEFT OUTER JOIN `Users` AS `User` 
ON `Posts`.`UserId` = `User`.`userId` WHERE `Posts`.`postId` = '2';

즉 nickname을 Posts 테이블에서 찾기 때문.

 

이걸 조인된 테이블에서 찾으려면 Post.nickname을 없애야 하는데, 이때 Sequelize.col()을 사용하니 해결되었다.


Solution

const post = await Posts.findOne({
            attributes: [
                "postId",
                "UserId",
                "title",
                "content",
                "createdAt",
                "updatedAt",                
                [Sequelize.col("nickname"), "nickname"]
            ],
            include: [{
                model: Users,
                attributes: []
            }],
            where: { postId }
})

// post
{
  "post": {
    "postId": 2,
    "UserId": 1,
    "title": "게시글 제목입니다.",
    "content": "content 입니다.",
    "createdAt": "2023-05-01T12:49:21.000Z",
    "updatedAt": "2023-05-01T12:49:21.000Z",
    "nickname": "Developer"
  }
}

attribute alias를 만들어주는 걸로 해결했는데... 맞는 해결 방법인지는 의문스럽다. 자세한 문서가 없는건지, 내가 못찾는 것인지...


Learned

아마 Sequelize 공식 문서는 나만 보기 어려운건 아니었나보다. 이런 글도 발견. ㅎㅎ

 

공식문서 짜증나서 내가 그냥 한 번에 정리하는 시퀄라이즈

시퀄라이즈 객체를 console 에 찍어보면 이런식으로 dataValues 외에 다른 값들이 추가적으로 많이 들어가있다. 바로 이 객체를 return 시에는 dataValues 만 자동으로 전달되기 때문에 문제가 없지만, 객

velog.io

공식문서에는 개별 메서드나 사용예시에 대한 친절한 설명이 띄엄띄엄... 불친절하다. 


 

'daily' 카테고리의 다른 글

3-Tier, 3-Layered Architecture  (0) 2023.05.09
23.05.06. Refresh token, Access token  (0) 2023.05.06
23, 17주차  (0) 2023.05.01
23.04.29. express routes index에서의 export 이름 설정  (0) 2023.04.29
23.04.29. Sequelize와 Mongoose의 차이?  (0) 2023.04.29