[Node] Mysql ORM으로 사용해보기 (3) - CRUD

Kim Tae Won·2022년 1월 21일
1

[Node] ORM 다루기

목록 보기
3/3
post-thumbnail

이전 글에 이어서, 이번 글에서는 데이터의 기초적인 CRUD에 대해 알아보겠다.

1. Create (생성)

1) build() & save()

build()의 경우 해당 모델의 객체를 생성해서 return하는 메소드이다. 앞으로 하나의 row가 될 객체이며, save() 메소드는 실제로 테이블에 해당 객체의 내용대로 새로운 row가 추가 된다.

유의할 점

  • save()의 경우 비동기 실행 함수라서 await을 해주지만, build()의 경우 비동기 실행 함수가 아닌 것을 유의하자.
  • 추가할 데이터에서 autoincrement를 설정한 부분(ex. id)의 경우 데이터에 추가해주지 않아도 자동으로 등록이 된다.
app.post('/api/members', async (req, res) => {
    const newMember = req.body;
    const member = Member.build(newMember);
    await member.save();
    res.send(member);
});

2) 'create()'

위 두개의 메소드가 하는 작업을 하나의 create()메소드로 수행할 수 있게 해준다. 훨씬 간단하게 사용이 가능해진다.

app.post('/api/members', async (req, res) => {
    const newMember = req.body;
    const member = await Member.create(newMember);
    res.send(member);
});

유의할 점

  • 아래 코드처럼 중간에 모델 객체에 어떤 수정을 하고 싶을 때에는, build(), save()메소드를 사용해야 한다.
app.post('/members', async (req, res) => {
  const newMember = req.body;
  const member = Member.build(newMember);
  member.name = 'Mike'; // name 프로퍼티 변경
  await member.save();
  res.send(member);
});

2. Read (조회)

1) findAll()

findAll()함수는 조건에 만족하는 모든 row(레코드)들을 조회해서 가져올 때 사용된다. findAll()을 쓰게 되면 Sequelize에 의해서 자동으로 SQL문으로 변환되어 DBMS에 전송된다. 이러한 변환기능이 ORM 기술의 핵심이다.

  • 아래 예시의 else 구문을 보면 모델이름.findAll()을 사용하였는데,이는 해당 모델의 모든 레코드들을 조회해가져오는 것이다.
  • if구문을 보면 조금 다른 점이 있다. 바로 where가 들어간 것이다. 특정 조건에 맞는 레코드들만 가져올 수 있게 된다.

    유의할 점

    • 모델이 가지는 대부분의 함수들을 promise를 반환하는 비동기 실행 함수라는 점이다. 따라서 아래 코드에서도 async, await을 통해 구현했다.
app.get('/api/members' , async (req, res) => {
    const { team } = req.query;
    if (team) {
        const teamMembers = await Member.findAll({ where: { team: team }});
        res.send(teamMembers);
    } else {
        const members = await Member.findAll();
        res.send(members);
    }
});

2) findOne()

테이블에서 특정 row(튜플) 하나만 조회하여 가져올 때 사용하는 메소드로, 아래 예제에서는 특정 직원의 레코드(튜플)을 가져오는데 사용된다. 조건을 설정하기 위해선 위에서 했던 것과 같이 where를 통해 사용하면 된다. 만약 조회 시에 여러 row들이 존재해도, 제일 첫 번째 row만 가져오게 된다.

app.get('/api/members/:id' , async (req, res) => {
    const { id } = req.params;
    //없으면 undefined 반환
    const member = await Member.findOne({ where: { id: id } });
    //위 코드와 동일함(JS 문법)
    //const member = await Member.findOne({ where: { id } });
    if (member) {
        res.send(member);
    } else {
        res.status(404).send({message : 'There is no such with the id!'});
    }
});

3. Update (갱신)

1) update()

특정 row들의 갱신은 update()메소드를 통해 해결할 수 있다. 모델이름.update() 메소드는 where의 조건을 만족하는 모든 row들의 변경할 컬럼 값을 새로운 값으로 갱신해주는 역할을 한다.
반환 값으로 Return하는 프로미스 객체는 작업의 성공결과로 배열 하나을 가지는데 해당 배열의 첫 번째 요소가 영향을 받은 row개수이다. 따라서 해당 정보를 통해 id 존재 여부도 파악할 수 있다.

유의할 점

  • 갱신을 위해 해당 row의 모든 정보를 보낼 필요는 없다. 변경되는 정보만을 보내는 것이 코드나 DBMS의 입자에서도 훨씬 간결해지게 된다. 예를 들어, 만약 이름을 변경하고 싶다면 해당 Member의 모든 정보가 아닌 name: 변경할 정보만을 담아 보내면 된다는 의미이다.
app.put('/api/members/:id', async (req, res) => {
    const { id } = req.params;
    const newInfo = req.body;
    const result = await Member.update(newInfo, { where: { id } });
    if (result[0]) {
        res.send({ message: `${result[0]} row(s) affected` });
    } else {
        res.status(404).send({ message : 'There is no such with the id!' });
    }
});

2) findOne() & save()

또 다른 갱신 방법으로는 findOne() 또는 findAll()을 통해 모델 객체(들)을 가져온 뒤 모델 객체(들)의 프로퍼티를 새로운 프로퍼티로 갱신하여 save()를 통해 테이블에 저장하는 방법이다. 조금 더 ORM을 실감나게 해주는 방법이다. 아래 예시에서는 findOne()을 통해 하나의 객체만을 가져와 정보를 갱신한 뒤 save()하여 테이블에 저장하였다.

app.put('/api/members/:id', async (req, res) => {
    const { id } = req.params;
    const newInfo = req.body;
    const member = await Member.findOne({ where: { id } });
    if (member) {
        Object.keys(newInfo).forEach((prop) => {
            member[prop] = newInfo[prop];
        });
        await member.save();
        res.send(member);
    } else {
        res.status(404).send({ message : 'There is no such with the id!' });
    }
});

4. Delete (삭제)

1) Model.destroy()

특정 row(들)의 삭제는 모델이름.destory() 메소드를 통해 구현할 수 있다. where 조건에 해당하는 모든 row(들)을 삭제해주는 메소드로, 실행이 되면 삭제된 row의 개수를 반환해 준다. 아래 예시와 같이 간단하게 작성이 가능해진다.

app.delete('/api/members/:id', async (req, res) => {
    const { id } = req.params;
    const deletedCount = await Member.destroy({ where: { id } });
    if (deletedCount) {
        res.send({ message : `${deletedCount} row(s) deleted!` });
    } else {
        res.status(404).send({message : 'There is no such with the id!'});
    }
});

2) Model객체.destroy()

또 다른 삭제 방법으로는 하나의 row에 대응하는 모델 객체가 가지고 있는 destroy()메소드가 있다. 위의 Model.destroy()는 static 메소드이며, 모델객체.destroy()는 static 메소드가 아닌 인스턴스 메소드이다. 먼저 findOne() 또는 findAll()을 통해 조회를 해서 해당 객체(들)을 가져온 뒤 destroy() 메소드를 통해 해당 row(들)을 삭제 가능하다.

app.delete('/api/members/:id', async (req, res) => {
  const { id } = req.params;
  const member = await Member.findOne({ where: { id } });
  // 여기에 코드를 추가하세요.
  if (member) {
    const result = await member.destroy();
    res.send({ message: "1 row(s) deteleted!" })
  } else {
    res.status(404).send({ message: 'There is no member with the id!' });
  }
});

유의할 점
실제 개발을 하면서 보게 될 코드는 둘 중 어느 것이든 될 수 있으므로 둘 다 잘 익혀놓자.

  • 이와 비슷하게 update 메소드 또한 static 메소드와 인스턴스 메소드 둘 다가 존재한다.

추가적인 메소드나 옵션들은 공식문서를 참조해 공부해보자

  • Model Querying - Basics
    • 기본적인 쿼리들에 대해 자세히 나와있다.
    • 꼭 한 번쯤 보길 바란다.
  • Model Querying - Finders
    • 조회에 관한 함수들과 옵션들을 조금 더 살펴볼 수 있다.
    • 매우 다양한 조회가 가능하다
  • Raw Queries
    • raw 쿼리(직접 SQL문을 작성)해서도 사용이 가능하다.
    • 성능을 필요로 하는 작업 등 복잡한 SQL문은 raw로 작성해야 한다고 한다.

참고

profile
꿈이 너무나 큰 평범한 컴공 대딩에서 취업 성공!

0개의 댓글