이 포스팅은 아래의 강의를 참고한 개인 정리본이니 강의를 통해 공부하시는 것을 추천드립니다.
1. 모든 데이터 삭제하기
mongoDB Compass에서 아래의 사진처럼 휴지통 버튼을 누르면 데이터베이스를 Drop 할 수 있다.
* ?? is not allowed to do action [dropDatabase] on [??]
권한이 없을 때 발생하는 에러.
Altas 유저의 권한을 변경해주면 된다.
DataBase User Privileges => Atlas admin 으로 설정되어 있나 확인
2. 임시 데이터 생성하기 (faker.js 이용)
아래의 설치 코드를 이용해 faker를 설치한다.
참고) faker.js 개발자가 최신 버전을 무한루프 돌리게 설정해놔서 구버전으로 설치
npm i faker@5.5.3
- faker 사용 방법
우선, userCount, boardsPerUser, commentsPerUser 인자를 받는다.
이 인자는 양의 정수만 받을 수 있다.
그 이후 각 받은 인자의 수 만큼 faker를 이용하여 배열에 임시 데이터를 넣어두고,
마지막에 몽고DB에 save하는 방식이다.
const faker = require("faker");
const { User, Board, Comment } = require("./src/models");
generateFakeData = async (userCount, boardsPerUser, commentsPerUser) => {
if (typeof userCount !== "number" || userCount < 1)
throw new Error("userCount 는 양의 정수여야 합니다.");
if (typeof boardsPerUser !== "number" || boardsPerUser < 1)
throw new Error("boardsPerUser 는 양의 정수여야 합니다.");
if (typeof commentsPerUser !== "number" || commentsPerUser < 1)
throw new Error("commentsPerUser 는 양의 정수여야 합니다.");
const users = [];
const boards = [];
const comments = [];
console.log("임시 데이터 준비중...");
for (let i = 0; i < userCount; i++) {
let g;
if(i % 2 == 0)
g = 'M';
else
g = 'W';
let name = faker.name.lastName();
// User 데이터 생성
users.push(
new User({
username: faker.internet.userName() + parseInt(Math.random() * 100), // 중복 방지를 위해 username 뒤에 랜덤 숫자를 넣음
name: name,
age: 20 + parseInt(Math.random() * 40), // 20~60이 나오도록
email: faker.internet.email(),
nickname: name + "'s nickname",
gender: g
})
);
}
// Board 데이터 생성
users.map( (user) => {
for (let i = 0; i < boardsPerUser; i++) {
boards.push(
new Board({
title: faker.lorem.words(),
content: faker.lorem.paragraphs(),
isUse: true,
user,
})
);
}
});
// Comment 데이터 생성
users.map((user) => {
for (let i = 0; i < commentsPerUser; i++) {
let index = Math.floor(Math.random() * boards.length); // comment를 넣을 boards 인덱스를 랜덤으로 조합
comments.push(
new Comment({
content: faker.lorem.sentence(),
user,
board: boards[index]._id,
})
);
}
});
console.log("===== 임시 데이터 삽입 시작 =====");
await User.insertMany(users);
console.log(`${users.length} 개의 사용자 데이터 생성 완료`);
await Board.insertMany(boards);
console.log(`${boards.length} 개의 게시판 데이터 생성 완료`);
await Comment.insertMany(comments);
console.log(`${comments.length} 개의 댓글 데이터 생성 완료`);
console.log("===== 임시 데이터 삽입 완료 =====");
};
module.exports = { generateFakeData };
이후 server.js ( 서버 메인 파일 ) 에서 호출하면 된다.
임시데이터 생성이 완료되었다면, 주석처리를 한다. (계속해서 임시데이터가 생성되는 것을 방지)
3. postman 대신 axios를 사용해보기
클라이언트 프레임워크인 react, vue 등을 사용하지 않고 JS만을 이용해서 간단하게 확인
1) axios 설치
커맨드 창에 npm i axios 을 입력해서 설치
npm i axios
2) frontend라는 폴더 생성 후 client.js 파일 생성
3) client.js를 따로 nodemon으로 실행
서버와 client.js를 동시에 nodemon으로 실행하고, 프로젝트 내에 파일을 변경(저장)하게 되면 client.js 측에서 오류가 발생하고 이 오류는 서버에 연결되지 못한다는 오류일 것이다.
왜냐하면, nodemon에서는 파일이 변경되는 순간 재시작을 하는데 client.js가 서버 재시작 도중에 연결을 시도하려고 하기 때문에 에러가 발생하는 것이다.
client.js를 수정했을 때에는 서버가 재시작되지 않길 원한다면 아래의 소스처럼 package.json에서 해당 nodemon 명령어에 --ignore 옵션을 사용하면 된다.
4) 기본적인 방법으로 axios 사용 및 데이터를 재구축해보기
위 소스의 흐름은 아래와 같다.
(아주 기본적인 axios 사용 및 데이터 재구성이므로 효율적이지 않은 소스)
A. board 데이터를 조회한다.
B. board 데이터가 배열형태로 조회되는데 board 데이터 하나 씩 확인한다. 무슨 확인을 하느냐
a. 해당 board 데이터의 user와 _id를 이용해서 user 데이터와 comment 데이터를 조회한다
b. boardOne에 방금 조회한 user, comment 데이터를 넣고 boards에 담는다.
C. board 첫 번째 데이터를 출력한다.
결과
* 위 소스의 문제점
N+1 문제가 발생함.
N+1 문제 : (간단 설명)Board 하나를 조회하기 위해 예상보다 큰 쿼리가 호출되는 것을 의미함.
A라는 Board에 30개의 Comment가 있을 경우 쿼리를 31번 호출해야하므로 비효율적
여기서 Comment 안에 연결되는 객체가 M개 있을 경우 31 * M 임.
참고) Javascript로 소요 시간 측정하기
console.time("START"); // 시작
// ... 소스들
console.timeEnd("END : "); // 끝
4. populate를 이용해서 자식 데이터 효율적으로 가져오기
아래의 소스처럼 populate를 이용하면 mongoose에서 알아서 userId를 이용해서 user부분을 user Document로 채워준다.
아래의 호출되는 쿼리를 보면 Board 데이터 20개를 조회했을 때 user가 중복되는 경우가 있는데 그것도 계산해서 user를 조회함. user.find에 7개만 호출함. 중복되는 데이터는 조회하지 않았다는 뜻.
+) virtual populate 사용하기
Comment는 Board 안에 있는 것이 아니라 Comment 안에 Board의 _id가 들어가있는 구조임.
이럴 때는 virtual populate를 사용할 수 있음.
아래 소스처럼 populate 부분을 배열로 바꾼 후 path 에 comments를 추가해준다.
이후 BoardSchema 에서 virutal 을 추가해준다.
5. 결론
위에서 일반적인 방법과 populate를 이용한 방법 중에서
당연하게도 populate를 이용한 방법이 월등히 성능이 좋았다.
다음 시간에는 또 다른 방법에 대해서 정리해보겠다.
'DB > MongoDB' 카테고리의 다른 글
[MongoDB 기초부터 실무까지] 9. Index, Paging(skip, limit) (0) | 2022.08.22 |
---|---|
[MongoDB 기초부터 실무까지] 8. 콜렉션 안에 다른 콜렉션 한 번에 저장해보기 (0) | 2022.08.17 |
[MongoDB 기초부터 실무까지] 6. Board API 만들기 및 라우터 안에 라우터 파라미터 사용 방법 (0) | 2022.08.05 |
[MongoDB 기초부터 실무까지] 5. Node.js로 MongoDB 접근해보기 (0) | 2022.08.01 |
[MongoDB 기초부터 실무까지] 4. Node.js 동기 프로그래밍(Callback, Promise, Await) (0) | 2022.07.27 |