그저 내가 되었고
항해99) 3주차:: 주특기 입문; 📚MongoDB → mongoose 본문
01. 준비하기
데이터베이스와 MongoDB의 개념
1) What is DB?
- DBMS: Database Management System: 단순히 데이터를 잘 저장하고 잘 찾기 위해 만들어진 소프트웨어
- server(DB server): DBMS가 설치된 서버 컴퓨터
- 흔히 "데이터베이스에 저장한다" 라고 말하면? 이 DBMS가 설치된 서버에 데이터를 저장한다고 말하는것
- 즉, DB 서버의 모든 데이터는 DBMS가 관리함
- DB의 종류
- 관계형 데이터베이스 - Relational Database (RDB): 데이터 형식이 정해져 있고, 데이터 끼리 관계를 맺어 모순이 없는(무결성과 정합성이 높은) 데이터를 유지할 수 있도록 도와주는것에 집중한 데이터베이스
- 비관계형 데이터베이스 - Non-relational Database (NoSQL): 관계형 데이터베이스에 속하지 않는 모든 데이터베이스. 데이터의 형태가 고정되어 있지 않고 유연하게 확장할 수 있음. 그러나 유연한 만큼 저장되는 데이터를 제대로 관리하지 않으면 데이터베이스에 저장된 데이터를 신뢰할 수 없게 되기도 함. 최근 많은 스타트업에서 유연한 설계를 위해 많이 채택되는 데이터베이스 유형
2) What is MongoDB?
- 국내, 외 수많은 개발자들에게서 사용되고있는 가장 인기있는 비관계형 데이터베이스(NoSQL) 중 하나
- 모든 데이터가 JSON 형태로 저장됨
- 복잡한 구조를 쉽게 저장할 수 있는 장점이 있음
- 무료
- 스케일 조정에 유리(쉽게 늘리고 줄일 수 있음)
3) 웹 서버 vs DB 서버
- 웹 서버: 웹 클라이언트가 원하는 데이터와 기능을 제공
- DB 서버: 데이터를 최대한 성능 좋게 저장하고 DB 클라이언트가 원하는 데이터를 제공
- IAN, 두 서버는 어떤것을 제공하는지만 다를 뿐 기본 원칙은 비슷함...
- 웹 서버는 DB 서버를 이용하는 DB 클라이언트가 될 수 있음~!! 브라우저-웹서버-DB서버 이런식으로 연결됨,,
02. 시작하기
MongoDB Client: Studio 3T 학습
1) Studio 3T:
API의 사용을 도와주는 API Client처럼 MongoDB를 위해서 만들어진 MongoDB Client(DB Client 종류 중 하나)!! Studio 3T의 GUI를 통해 MongoDB에 저장된 데이터를 관리하기 쉽게 보여준당
2) DB Client vs API Client:
서버에 연결해 데이터를 보내는것 까지는 같은 개념이지만 DBMS는 웹처럼 단순하지 않아 프로그램 사용법이 조금 더 복잡하고 DB의 데이터를 조회하거나, 관리할 수 있는 기능을 제공
3) 데이터 제어 명령어? Studio 3T 자체에서 쓰는 애들👇🏻👇🏻
- db.collectionName.find({})
- db.collectionName.insertOne({ key: "value", key2: "값" })
- db.collectionName.deleteOne({ _id: ObjectId("...")})
코드에서 MongoDB 이용
1) 내 코드에서 MongoDB에 연결하려면 뭘 해야 하려나~?
: mongoose 설치해서 기기~ 설치는,, 개쉬움
2) 그냥 작업하던 플젝에서 터미널창에 npm install mongoose 입력하면 끗ㅋ
3) mongoose의 문서(document)?!
- MongoDB에서 가지고 있는 각 데이터 하나하나
- 1개 이상의 Key-Value의 쌍으로 이루어져있음.
{
"_id": ObjectId("6682192a1c155bd2f27881"),
"name": "lyw",
}
4) mongoose의 컬렉션(Collection)이란?
- JSON 형식의 여러가지 문서(Document)를 보유할 수 있음
- 이후에 설명할 관계형 데이터베이스(RDB)의 Table과 동일한 역할을 함
5) mongoose의 스키마(Schema)란?
- 컬렉션(Collection)에 들어가는 문서(Document)에 어떤 종류의 값이 들어가는지를 정의
- 데이터를 모델링할 때 사용
- 대표적인 스키마 타입? null, string, number, date, butter, boolean, objectId(Schema.Types.ObjectId: 다른 객체를 참조할 때 넣음), array
6) mongoose의 모델(Model)이란?
- 데이터베이스에 데이터를 저장해줄때 데이터의 구조를 담당
- 스키마를 사용하여 만들고, MongoDB에서 실제 작업을 처리할 수 있는 함수들을 지니고 있음
- 문서(Document)를 생성할 때 사용
7) 웹 서버에서 MongoDB에 연결
- 우리가 만들 Directory Structure::
.
├── app.js
├── routes
│ ├── carts.js
│ └── goods.js
└── schemas
├── index.js
├── cart.js
└── goods.js
- mongoose를 이용해 데이터베이스에 연결
/schemas/index/js 예시
const mongoose = require("mongoose"); //mongoose 라이브러리 가져와서 connect
const connect = () => {
mongoose
.connect("mongodb://localhost:27017/sparta_prac") //여기에 연결하고 sparta_prac이란 db에 연결한다
.catch(err => console.log(err)); //connect가 실패(몽고db에 연결 실패)하면 에러처리 진행(콘솔로그로 발생한 에러 보여주세요~!)
};
mongoose.connection.on("error", err => console.error("몽고디비 연결 에러", err)); //몽구스 커넥션 실패하면 콘솔 에러로 보여줌
module.exports = connect; //현재 모듈에서 connect를 내보내줘서 밖에서 mongodb랑 연결하고 사용할 수 있게 해 줌
app.js 예시
const connect = require("./schemas"); //connect라는 변수로 require로 ./schemas의 모듈 갖고 올 것.
//노드에서는 모듈 갖고 올 때 폴더 이름까지만 지정해줘도 자동적으로 index 파일 갖고올 수 있음
connect();
8) 상품 모델 작성:mongoose를 더 편하게 사용하기 위한 방법! Schema를 생성하여 데이터를 관리하기 위해 모델을 작성.
/schemas/goods.js 예시
//실제 상품 모델 작성. 몽고디비에선 스키마를 작성한다고 함. 굿즈라는 파일에서 굿즈라는 스키마 작성.
const mongoose = require("mongoose");
const goodsSchema = new mongoose.Schema({ //몽구스에 스키마를 새롭게 정의한다는 뜻
goodsId: { //내부의 이렇게 하나하나 중괄호들이 들어가는 스키마!! goodsId 이런게 하나하나 키값인데,
//얘들이 어떤 타입인지. 무조건 필요한지. 유니크한값 필요한지 하나하나 상세하게 알려줄 수 있음.
type: Number,
required: true,
unique: true
},
name: {
type: String,
required: true,
unique: true
},
thumbnailUrl: {
type: String
},
category: {
type: String
},
price: {
type: Number
}
});
module.exports = mongoose.model("Goods", goodsSchema);
9) 상품 생성 API 작성
- 상품 데이터를 코드에 넣어두는게 아닌, 데이터베이스에 추가할 수 있게 해봅시당
- 지금까지 만든 API는 상품 목록 조회, 개별 상품 조회 로 모두 조회하는 API!!
- 그러니 이제는 GET 메서드 뿐만 아니라 POST와 같은 메서드에 대응하는 API도 개발ㄱㄱ~
- REST API 에 따르면 새로운 데이터를 추가하는 method는 POST 를 쓰는 것을 권장
- POST 메소드의 특징은 GET 메소드와는 다르게 body 라는 추가적인 정보를 담아 서버에 전달 할 수 있기 때문에 정보값을 body라는 이름으로 넘겨줄 예정
- /app.js 예시
+ body로 전달 받은 JSON 데이터를 바로 사용할 수 없음!
+ Express.js에서 제공하는 JSON middleware를 사용해 body로 전달된 데이터를 사용할 수 있도록 해야함!
++주의점; middleware(app.use(express.json()); - app이란 객체에 use라는걸 호출해서 express.json()이란 미들웨어를 거치도록 하는 것. 결국은 전역 미들웨어를 하는 것.... 뭔소리야ㅆㅣ발)가 app.use("/api", [goodsRouter]) 보다 위에 작성되어야 함. 미들웨어는 순차적으로 거쳐가기 때문!!! 만약에 /api에 해당하는 router부터 가게 되면 Json middleware를 사용해 body로 전달된 데이터를 사용할 수 있도록 변경되지 않은 상태이므로 그러면 안됨안됨
- /routes/goods.js 예시
const Goods = require("../schemas/goods"); //스키마 선언한 굿즈 스키마 가져와서 굿즈라는 변수에 할당한 굿즈를 실제로 API 동작시 사용할 것
router.post("/goods", async (req, res) => {
const {goodsId, name, thumbnailUrl, category, price} = req.body; //post 메소드로 요청 했을 때 body에 데이터가 있었다면
//있는 데이터를 객체 구조 분해 할당을 통해 가지고 오란 것(내부에 들어갈 데이터는 저렇게 goodsId부터 4개)
const goods = await Goods.find({goodsId}); //데이터 조회는 find 명령어 씀. goodsId에 해당하는 값이
//존재하는지에 대해서 확인한 후, 그 값이 있거나 없거나 무조건 goods란 변수에 할당.
if (goods.length) { //만약 goods란 변수에 데이터가 존재한다면
return res.status(400).json({success: false, errorMessage: "이미 있는 데이터입니다."}); //만약 데이터 삽입 전 동일 데이터가
//존재하는것을 확인 했었다면 status 400번 코드로, json 형식으로 반환할 것.
} //goods라는 데이터가 똑같이 존재하지 않는다면 goods란 스키마를 통해서 데이터를 생성할 것.
//goodsId, name 등등 이런걸 통해서 데이터 생성하고 생성된 데이터를 createdGoods에 할당해서
const createdGoods = await Goods.create({goodsId, name, thumbnailUrl, category, price});
res.json({goods: createdGoods}); //res.json 형식으로 이런 goods가 생성되었다고 반환
});
+ API 작성이 완료되면 Thunder Client로 상품 생성 API를 호출해보세용
+ post에 http://localhost:3000/api/goods 적구 send 클릭클릭
+ 이번에는 Body에 추가할 정보값을 입력해보까요. 아래의 예시를 넣어서 Json Content 안에 넣어준뒤 Send 버튼을 눌러서 호출 기기
{
"goodsId": 2,
"name": "시원한 콜라",
"thumbnailUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRk7JqMw7ZYZP4ZW136wcoMTmLzbrMIJzUWb1Dhu9cHwCPp0gA&usqp=CAc",
"category": "drink",
"price": 3000
}
10) 저장된 데이터 Studio 3T로 확인
Success 메시지를 확인한 후 Studio 3T를 열어 hyuni_mall 데이터베이스를 새로고침 해보면 방금 입력한 데이터가 MongoDB에 들어간것을 확인할 수 이뜸
03. 장바구니 구현(1)
데이터베이스와 MongoDB의 개념
1) 장바구니를 구현하기 위해서는 어떤 기능들이 필요할까염?
보통 이런 👇🏻게 필요해여
- 장바구니 목록 조회
- 장바구니에 상품 추가
- 장바구니의 상품 제거
- 장바구니의 상품 수량 수정
2) 장바구니 모델 작성
- 이제 상품을 장바구니에 담기 위한 모델을 작성해볼까유
- 어떤 데이터를 넣어야 할까여? 어떤 상품을 담았는지, 몇 개를 담았는지 알 수 있어야죠~!
- /schemas.cart.js 예시
const mongoose = require("mongoose");
const cartSchema = new mongoose.Schema({
goodsId: {
type: Number,
required: true,
unique: true
},
quantity: {
type: Number,
required: true
}
});
module.exports = mongoose.model("Cart", cartSchema);
3) 장바구니 목록 조회 API 작성
- 첫째로 장바구니의 데이터를 찾아줌
- 그리고 장바구니 데이터베이스에는 goodsId와 quantity 정보밖에 담겨있지 않기 때문에 장바구니에 담겨있는 상품의 아이디에 맞는 상품 정보를 한번 더 찾아와 가져옴
- 아래처럼 나오는게 목적!
{
"carts": [
{
"quantity": 10,
"goods": {
"goodsId": 3,
"name": "시원한 콜라3333",
"thumbnailUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRk7JqMw7ZYZP4ZW136wcoMTmLzbrMIJzUWb1Dhu9cHwCPp0gA&usqp=CAc",
"category": "drink",
"price": 3000
}
},
{
"quantity": 3,
"goods": {
"goodsId": 1,
"name": "시원한 콜라1",
"thumbnailUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRk7JqMw7ZYZP4ZW136wcoMTmLzbrMIJzUWb1Dhu9cHwCPp0gA&usqp=CAc",
"category": "drink",
"price": 3000
}
}
]
}
- 그럼 routes/carts.js 파일을 생성해서 작성 시작해봅시당
/routes/carts.js 예시
const express = require("express");
const Goods = require("../schemas/goods");
const Cart = require("../schemas/cart");
const router = express.Router();
router.get("/carts", async (req, res) => {
const carts = await Cart.find();
const goodsIds = carts.map((cart) => cart.goodsId);
const goods = await Goods.find({ goodsId: goodsIds });
const results = carts.map((cart) => {
return {
quantity: cart.quantity,
goods: goods.find((item) => item.goodsId === cart.goodsId)
};
});
res.json({
carts: results,
});
});
module.exports = router;
/app.js 예시
const cartsRouter = require("./routes/carts");
app.use("/api", [goodsRouter, cartsRouter]);
- API가 잘 동작하는지 확인?! get으로 http://localhost:3000/api/carts 호출!~!
그러면,, Status는 200 이 나왔지만 Response 안에 carts에 빈 배열이 오는 것이 정상. 아직 장바구니에 아무것도 추가 안했으니까~!
{
"carts": []
}
04. 장바구니 구현 (2)
1) 장바구니에 상품 추가 API 작성: 상품 추가 API와 거의 비슷하다용
- 구현하려면 어떤 값이 필요할까?! goodsId와 quantity~!
- 어떻게 구현해야할까!? POST 메서드와 /goods/:goodsId/cart 주소에 대응하는 API를면 되지!~
- 이후 받아온 :goodsId 값을 통해 이미 장바구니에 상품이 들어가 있는지 확인 후,
- 장바구니에 존재하면 수량만 수정하고,
- 존재하지 않는다면 새로운 카트에 상품정보를 새로 생성하도록 해보자!!!!
- /routes/goods.js 예시
const Cart = require("../schemas/cart");
router.post("/goods/:goodsId/cart", async (req, res) => {
const { goodsId } = req.params;
const { quantity } = req.body;
const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
if (existsCarts.length) {
return res.json({ success: false, errorMessage: "이미 장바구니에 존재하는 상품입니다." });
}
await Cart.create({ goodsId: Number(goodsId), quantity: quantity });
res.json({ result: "success" });
});
- http://localhost:3000/api/goods/:goodsId/cart 여기 url에 수정을 원하는 :goodsId값을 넣어준 후 body에 quantity 값을 json 형태로 입력한 뒤 Post method로 요청 기기
{
"quantity": 2
}
그 후 json 형태로 "result": "success" 메세지 잘 출력되면 Studi 3T에서 새로고침 하셈! carts document에 장바구니 데이터 저장된것을 확인 가능쓰~!
2) 장바구니의 상품 수량 수정 API 작성
- 장바구니에 상품 추가 API와 굉장히 비슷해여
- 하지만 이번에는 POST 메소드가 아닌 PUT 메소드를 사용해 데이터를 update 해줄검당
- URI는 추가 API와 같은 포맷을 가지고 있지만, 이번 API에서는 간단하게 goodsId를 이용해서 상품정보가 장바구니내에 존재한다면 body를 통해 받아온 quantity 값에 맞게 상품 수량을 수정해 줘봅시당
- /routes/goods.js 예시
router.put("/goods/:goodsId/cart", async (req, res) => {
const { goodsId } = req.params;
const { quantity } = req.body;
const existsCarts = await Cart.find({ goodsId: Number(goodsId) });
if (existsCarts.length) {
await Cart.updateOne({ goodsId: Number(goodsId) }, { $set: { quantity } });
}
res.json({ success: true });
})
- http://localhost:3000/api/goods/:goodsId/cart에 put설정 후 :goodsId에 수량까지 body에 json으로 기입해서 send기기
- success:true 뜨면 studio3T에서 쳌쳌
3) 장바구니의 상품 제거 API 작성
- 장바구니에 상품 추가 API 와 동일한 URI를 사용할거여
- 하지만 이번에는 간단하게 goodsId를 통해 상품이 장바구니 안에 존재한다면 장바구니 내에서 상품 정보를 삭제할껴
- /routes/goods.js 예시
router.delete("/goods/:goodsId/cart", async (req, res) => {
const { goodsId } = req.params;
const existsCarts = await Cart.find({ goodsId });
if (existsCarts.length > 0) {
await Cart.deleteOne({ goodsId });
}
res.json({ result: "success" });
});
↳데이터를 지울 때는 보통 DELETE method 를 사용(당연한거 아님...? 암튼...;;) 지우는 행동에서는 URL 만으로 지워야할 리소스를 명시하는데 충분하다는 이유로...
- http://localhost:3000/api/goods/:goodsId/cart에서 delete 메소드 통해 호출하면 success 메세지 뜨고 Studio3T에서 삭제된 것 눈으로 확인 가능쓰
'개발 > 항해99 9기' 카테고리의 다른 글
항해99) 3주차:: 주특기 입문; 개인과제 전체 코드(JS) (0) | 2022.10.07 |
---|---|
항해99) 3주차:: 주특기 입문; 장바구니 전체 코드(JS) (0) | 2022.10.03 |
항해99) 3주차:: 주특기 입문; 📚Express.js (0) | 2022.10.03 |
항해99) 2주차:: 💡2주차 맺음 WIL; 알고리즘 관련 중요 정리 + 소회✍🏻 (0) | 2022.10.02 |
항해99) 2주차:: Algorithm Test(JS) (0) | 2022.09.30 |