개발일지

개발일지 40일차

index.ys 2023. 4. 28. 01:01

2주차 시험 오답풀이

  • GET /posts/like API 내부에서 함수 표현식을 이용해 호이스팅을 발생시켜 오류 출력하기
  • 함수 표현식을 이용해 변수에 함수를 할당할 경우 발생하는 호이스팅 문제점을 인지해야한다.

수정전

router.get('/like', authMiddleware, async (req, res) => {
  try {
    const { userId } = res.locals.user;

    const posts = await Posts.findAll({
      attributes: [
        'postId',
        'title',
        'createdAt',
        'updatedAt',
        [sequelize.fn('COUNT', sequelize.col('Likes.PostId')), 'likes'],
      ],
      include: [
        {
          model: Users,
          attributes: ['userId', 'nickname'],
        },
        {
          model: Likes,
          attributes: [],
          required: true,
          where: {
            [Op.and]: [{ UserId: userId }],
          },
        },
      ],
      group: ['Posts.postId'],
      order: [['createdAt', 'DESC']],
      raw: true,
    }).then((likes) => parseLikePostsModel(likes));

    // Like와 Post모델을 Join한 결과를 Plat Object로 변환하는 함수
      const parseLikePostsModel = (likes) => {
          return likes.map((like) => {
            let obj = {};

            for (const [k, v] of Object.entries(like)) {
              if (k.split('.').length > 1) {
                const key = k.split('.')[1];
                obj[key] = v;
              } else obj[k] = v;
            }
            return obj;
          })
        }

    return res.status(200).json({
      data: posts,
    });
  } catch (error) {
    console.error(`${req.method} ${req.originalUrl} : ${error.message}`);
    console.error(error);
    return res.status(400).json({
      errorMessage: '좋아요 게시글 조회에 실패하였습니다.',
    });
  }
});

수정후

-  parseLikePostsModel함수의 호출부가 선언부 보다 위에있어 함수의 선언부를 호출부 위로 끌어올려주는 수정을 했어야했다.

router.get('/like', authMiddleware, async (req, res) => {
  try {
    const { userId } = res.locals.user;
    
   // Like와 Post모델을 Join한 결과를 Plat Object로 변환하는 함수
      const parseLikePostsModel = (likes) => {
          return likes.map((like) => {
            let obj = {};

            for (const [k, v] of Object.entries(like)) {
              if (k.split('.').length > 1) {
                const key = k.split('.')[1];
                obj[key] = v;
              } else obj[k] = v;
            }
            return obj;
          })
        }

    const posts = await Posts.findAll({
      attributes: [
        'postId',
        'title',
        'createdAt',
        'updatedAt',
        [sequelize.fn('COUNT', sequelize.col('Likes.PostId')), 'likes'],
      ],
      include: [
        {
          model: Users,
          attributes: ['userId', 'nickname'],
        },
        {
          model: Likes,
          attributes: [],
          required: true,
          where: {
            [Op.and]: [{ UserId: userId }],
          },
        },
      ],
      group: ['Posts.postId'],
      order: [['createdAt', 'DESC']],
      raw: true,
    }).then((likes) => parseLikePostsModel(likes));


    return res.status(200).json({
      data: posts,
    });
  } catch (error) {
    console.error(`${req.method} ${req.originalUrl} : ${error.message}`);
    console.error(error);
    return res.status(400).json({
      errorMessage: '좋아요 게시글 조회에 실패하였습니다.',
    });
  }
});

lv4과제

- db에 migrate하기

npx sequelize db:migrate

- db에 migrate 되돌리기

npx sequelize db:migrate:undo

- model파일 생성하기

npx sequelize model:generate --name Posts --attributes title:string,content:string,password:string

app.js 수정

- router를 좀 더 효율적으로 처리하기 위해 공통된 경로끼리 묶어주고 아닌 경로를 따로 나눠주는 처리를 하였다.

app.use(express.json());
app.use(cookieParser());
app.use('/posts', [likeRouter, postsRouter, commentRouter, authRouter]);
app.use('/', authRouter);​

Posts.js Model 작성

  • targetKey:참조 되는 키
  • sourceKey: 소스 키
  • foreingnKey: 외래 키 ,다른 테이블에 특정 키를 참조

soureceKey와 targetKey는 동일해야하고, foreignKey는 참조하는쪽과 참조 되는쪽이 동일해야한다.

 static associate(models) {
      this.hasMany(models.Posts, {
        sourceKey: 'userId',
        foreignKey: 'UserId',
      });
      this.hasMany(models.Likes, {
        sourceKey: 'userId',
        foreignKey: 'UserId',
      });
      this.hasMany(models.Comments, {
        sourceKey: 'userId',
        foreignKey: 'UserId',
      });

Usres.js Model 작성

    static associate(models) {
      this.belongsTo(models.Users, {
        targetKey: 'userId',
        foreignKey: 'UserId',
        onDelete: 'CASCADE',
      });
      this.hasMany(models.Likes, {
        sourceKey: 'postId',
        foreignKey: 'PostId',
      });
      this.hasMany(models.Comments, {
        sourceKey: 'postId',
        foreignKey: 'PostId',
      });

관계설정

  • hasMany: 1: n 관계에서 참조하는 테이블이 되는 쪽에 설정해줌
  • belonsTo: 참조받는 테이블에서 설정

Migration 관리방법

- migration파일을 날짜별로 관리한다. migration파일은 결국 현재 db상태를 업데이트, 다음 업데이트에서는 어떤 상태로 변경할 것인지를 의미

 

- 하나의 db를 사용함, 실제 서비스 개발시 실제고객이 사용하는 db와 개발,테스트용 db로 나누어져 사용

 

- 개발용 db는 실수하면 밀어버리고 재생성이 가능하지만, 서비스용 데이터는 실제고객이 사용하고 있기때문에 삭제 불가,

 그렇기 때문에 migration파일을 날짜별, 버전별로 수정해야함

Model 파일

- model은 서버에서 db를 어떻게 바라보는지 설정, db와 서버는 완전히 다른 개체이기때문에 서버가 db를 이해하기 위한 수단중 하나가 ORM을 이용해 이해하는 방법, migration은 db셋팅도 서버에서 할 수 있게 도와주는 요소

 

- model은 db를 서버와 실제로 이어주는 역할(ORM), migration은 db셋팅의 역할

오늘 생성한 users데이터

에러처리

- 과제의 단계가 오르면 오를수록, 코드의 길이가 길어지면 길어질수록 에러가 자주뜬다 에러를 자주보다 보면 공통적인

에러들이 자주 발생한다. 그게 아니더라도 에러를 자세히 읽어보면 대부분 어느부분에서 에러가 발생되었는지 확인할 수 있다는걸 느꼈다

오늘 발생한 에러들

- 미들웨어 정의오류

- 오타

- 에러는 아니지만 db에 설정된 컬럼의 값이 들어가지 않아 db를 drop하고 migration파일을 수정한다음에 다시 db를 생성해주었다. 

- 기타오류

db에 수정할 내용이 생기면 db를 drop하는 방법말고, migration파일을 이용해 수정하는 방법을 연습해야겠다 sql을 이용한 방법이나 cli를 이용하여 db를 수정하는 방법을 사용하고 날짜별로 migration파일을 관리하는 방법의 필요성을 느꼈다.