기본구조
import mongoose from 'mongoose' // defaultSchema를 정의합니다. const defaultSchema = new mongoose.Schema({ defaultId: { // 이 필드는 실제 사용될 데이터의 이름입니다. type: Number, // 이 필드의 데이터 타입이 숫자임을 나타냅니다. required: true, // 이 필드가 반드시 있어야 함을 나타냅니다. unique: true // 이 필드의 값이 유일해야 함을 나타냅니다. } }); // defaultSchema를 사용하여 'Defaults'라는 이름의 mongoose 모델을 생성합니다. export default mongoose.model("Defaults", defaultSchema);
아래와 같은 요구사항에 맞춰 스키마를 생성하면 다음과 같다.
/schema/goods.js파일을 생성한 후 구현해주세요!- 스키마의 이름은
goodsSchema입니다.- 요구사항 구현이 완료되었으면, 해당하는 스키마를 ‘Goods’ 이름을 가진
mongoose모델로export해주세요!
goodsId
- 숫자 타입, 필수 항목, 중복값 허용X
name
- 문자열 타입, 필수 항목, 중복값 허용X
category
- 문자열 타입
price
- 숫자 타입
import mongoose from 'mongoose'
// defaultSchema를 정의합니다.
const goodsSchema = new mongoose.Schema({
goodsId: { // 이 필드는 실제 사용될 데이터의 이름입니다.
type: Number, // 이 필드의 데이터 타입이 숫자임을 나타냅니다.
required: true, // 이 필드가 반드시 있어야 함을 나타냅니다.
unique: true // 이 필드의 값이 유일해야 함을 나타냅니다.
},
name : {
type : String,
required: true,
unique: true
},
thumbnailUrl: {
type : String
},
category : {
type : String
},
price : {
type : Number
}
});
// defaultSchema를 사용하여 'Defaults'라는 이름의 mongoose 모델을 생성합니다.
export default mongoose.model("Goods", goodsSchema);
순서는
1. mongoose
2. API 구현
3. 클라이언트로부터 전달받은 데이터를 가져온다.
4. goodsId 중복되지 않았는지 검사
4-1. 중복 시 에러메시지 응답
5. 상품 생성
6. 생성된 상품 정보 클라이언트에게 응답
// routes/goods.js
import express from 'express';
//1. mongoose, Goods 모델 가져오기
import mongoose from 'mongoose';
import Goods from '../schemas/goods.js'
const router = express.Router();
//2. API 구현
/** 상품 등록 **/
// localhost:3000/api/goods POST
router.post('/goods', async (req, res) => {
//3. 클라이언트로부터 전달받은 데이터를 가져온다.
const { goodsId, name, thumbnailUrl, category, price } = req.body;
//4. goodsId 중복되지 않았는지 검사
//4-1. 중복 시 에러메시지 응답
const goods = await Goods.find( { goodsId }).exec(); //await를 쓰려면 exec()를 꼭 써줘야함. 안그럼 오류뜸
//여기서의 Goods는 스키마. 스키마를 통해서 goodsId를 기반으로 찾을거임!
//데이터를 생성할때 사용 X. 데이터 조회할때만 사용!
if (goods.length) {// goods의 요소가 있다면 true, 없다면 false
return res.status(400).json("이미 존재하는 데이터!")
}
//5. 상품 생성
const createGoods = await Goods.create({
goodsId,
name,
thumbnailUrl,
category,
price
})
//6. 생성된 상품 정보 클라이언트에게 응답
return res.status(201).json({ goods : createGoods })
})
export default router;

정상작동됐을때와 다르게 프리뷰에서는 따로 내용은 안나오고 그렇다고 error가 뜨지 않고, 201 상태코드가 떴다. 그럼 데이터는 잘들어갔을까?

반역자 환타가 잘 들어간걸 확인할 수 있었다.
==> 데이터베이스를 이용하는 경우 async, await, exec()를 넣어야하는데 이유는 데이터를 조회하는 동안 프로그램이 멈추는 경우가 있어서 정상적으로 데이터가 조회되지않을수있음. 위와같이 insomnia에서 값은 들어갔지만 프리뷰에서 뜨지 않은 이유인가보다.
이렇게 저장하고, app.js를 실행해서 서버를 키고 insomnia에서 API가 잘굴러가는지 확인할 수 있다.

send를 누르면 이상이 없다면 아래와 같이 201 created와 함께 입력된 값들이 나온다.

처음 만들었던 스키마의 기준을 벗어나버리면 오류가 떠버린다. 중복값 비허용을 해놨기때문에 발생한 오류이다. 

good.js 에서 rounter를 중복이라면 오류가 잡히도록 만들어놨기때문에 잡힌 오류이다.

그럼 mongoDB에는 잘 올라갔을까? studio3T를 통해 확인해보면 잘 들어갔음을 확인할 수 있다.


이번에 만드게 될 [할 일 메모 사이트]는 Express를 통해 MongoDB를 사용하고, REST API를 설계하고 구현하는 작업
[할 일 메모 사이트]에서 구현할 기능
1. 할 일 추가하기
2. 할 일 목록 보기
3. 할 일 내용 변경하기
4. 할 일 순서 변경하기
5. 할 일 완료하기
6. 할 일 완료 해제하기
1. 새 폴더 생성 -> yarn init -y 로 프로젝트 초기화
2. yarn add express mongoose 설치
3. ES6를 사용할거니까 package.json에 "type": "module" 를 추가
4. app.js에서 모든걸 실행할 예정
import express from 'express';
const app = express();
const PORT = 3000;
// Express에서 req.body에 접근하여 body 데이터를 사용할 수 있도록 설정합니다.
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('./assets'));//assets를 바탕으로 서빙할거다
const router = express.Router();
router.get('/', (req, res) => {
return res.json({ message: 'Hi!' });
});
app.use('/api', router);
app.listen(PORT, () => {
console.log(PORT, '포트로 서버가 열렸어요!');
});
5. 프론트 파일을 불러와서 assets 폴더에 넣어주고,
app.js에서 아래와 같은 미들웨어를 이용하여 assets폴더에 있는 정적인 요소들을 서빙해준다.
app.use(express.static('./assets'));
다 만들고나서 서버 실행 -> todo 내용을 Json으로 입력하고, 유효성검사가 잘 돌아가는지 확인하기 위해 같은거를 입력하려고 하자 아래와 오류가 나면서 서버가 멈췄다.

유효성검사 에러..? 값을 숫자로 묶는걸 실패해..?

이 코드에서 todoMaxOrder 가 숫자가 아닐 수 있다는걸 말하는 듯 했다.
그렇다면 형변환을 시켜주겠어!


send를 보내면 오류는 뜨지않지만, DB에서는 
같은 값이 계속 쌓이고 있다. 유효성 검사한게...이상이 있던거였다!
그러다가 발견했다. 아 order의 값을 변경해야하는데 내가 order의 속성을 안불러왔다는걸

그래서 넣고 다시 하니 정상작동됐다.

같은 걸 넣으면 order의 값이 올라간다. 이야~~ get도 잘 구동한다.

- 해야 할 일(
value):
- 할 일의 내용을 나타내는 문자열(
String) 형식의 데이터입니다.- 해야 할 일의 순서(
order):
- 할 일의 순서를 나타내는 숫자(
Number) 형식의 데이터입니다.- 완료 날짜(
doneAt):
- 할 일이 언제 완료되었는지 나타내는 날짜(
Date) 형식의 데이터입니다.- 완료되지 않았다면
null, 완료 되었다면 날짜(Date) 형식의 데이터를 가지게됩니다.
const TodoSchema = new mongoose.Schema({
value: {
type: String,
required: true, // value 필드는 필수 요소입니다.
},
order: {
type: Number,
required: true, // order 필드 또한 필수 요소입니다.
},
doneAt: {
type: Date, // doneAt 필드는 Date 타입을 가집니다.
required: false, // doneAt 필드는 필수 요소가 아닙니다.
},
});
//app.js
import express from 'express';
import connect from './schema/index.js';
import Todo from './schema/todo.schema.js';
import todosRouter from './routes/todos.router.js';
const app = express();
const PORT = 3000;
connect();
// Express에서 req.body에 접근하여 body 데이터를 사용할 수 있도록 설정합니다.
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('./assets'));//assets를 바탕으로 서빙할거다
const router = express.Router();
router.get('/', (req, res) => { //이건 그냥 샘플이었음
return res.json({ message: 'Hi!' });
const value = Todo.find( { v})
});
app.use('/api', [router,todosRouter]);
app.listen(PORT, () => {
console.log(PORT, '포트로 서버가 열렸어요!');
});
// /routes/todos.router.js
import express from 'express';
import Todo from '../schema/todo.schema.js'
const router = express.Router();
/** 할 일 등록 **/
// localhost:3000/api/todos POST
router.post('/todos', async (req, res) => {
//1. 클라이언트로부터 받아온 value 데이터를 가져오기
const { value } = req.body;
//1-2. 만약 클라이언트가 value 데이터를 입력하지 않으면 클라이언트한테 알리기
if (!value) {
return res.status(400).json({ errorMessage: "해야할 일(value) 데이터가 존재하지않습니다."})
}
//2. 해당하는 마지막 order 데이터를 조회
//sort() 인자는 어떤 컬럼을 조회할건지 적는거임. order를 정렬하는데 내림차순(-)으로 한다는말임
const todoMaxOrder = await Todo.findOne().sort('-order').exec();
//3. 만약 마지막 order 데이터가 존재한다면 현재 해야할 일을 -1하고, oreser 데이터가 존재하지않는다면 1로 할당.
const order = todoMaxOrder ? todoMaxOrder.order + 1 : 1;
//4. 해야할 일 등록
const todo = new Todo({ value, order }); //왜 create로 안하지? //todo라는걸 인스턴스로 만든것
await todo.save(); // 실제 데이터 베이스 저장
//5. 해야할 일을 클라이언트에게 반환
return res.status(201).json({ todo: todo });
})
/** 할 일 목록 조회 **/
// localhost:3000/api/todos GE
router.get('/todos', async(req, res) => {
//1. 해야할 일 목록 조회
const todos = await Todo.find().sort('-order').exec();
//2. 해야할 일 목록 조회 결과를 응답
return res.status(200).json({todos})
})
export default router;