이전 글에 이어서, 이번 글에서는 데이터의 기초적인 CRUD에 대해 알아보겠다.
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);
});
위 두개의 메소드가 하는 작업을 하나의 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); });
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);
}
});
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!'});
}
});
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!' });
}
});
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!' });
}
});
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!'});
}
});
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로 작성해야 한다고 한다.
참고