
8-1. NoSQL vs SQL
MySQL은 SQL을 사용하는 대표적인 데이터베이스인 반면에, 몽고디비는 대표적으로 NoSQL이라 불리는 데이터 베이스이다.
| SQL(MySQL) | NoSQL(몽고디비) |
| 규칙에 맞는 데이터 입력 테이블 간 JOIN 지원 안정성, 일관성 용어(테이블, 로우, 칼럼) |
자유로운 데이터 입력 컬렉션 간 JOIN 미지원 확장성, 가용성 용어(컬렉션, 다큐먼트, 필드) |
8-4. 데이터 베이스 및 컬렉션 생성하기
| MongoDB 시작 | $ mongo admin -u [이름] -p [비밀번호] | 관리자 권한으로 MongoDB 셸에 접속 |
| DB 선택/생성 | > use [데이터베이스명] | 해당 DB로 전환. 존재하지 않으면 자동 생성 (데이터 입력 시 목록에 표시). |
| 현재 DB 확인 | > db | 현재 사용 중인 데이터베이스 이름을 출력 |
| DB 목록 확인 | > show dbs | 생성된 DB 목록을 보여줌 |
| 컬렉션 생성 | > db.createCollection('컬렉션명') | 컬렉션을 직접 생성 |
| 자동 생성 | (별도 명령어 없음) | 다큐먼트 입력 시 컬렉션이 자동 생성 |
| 컬렉션 목록 확인 | > show collections | 현재 DB의 컬렉션 목록을 보여줌 |
8-5. CRUD 작업하기
8.5.1 Create(생성)
컬렉션에 컬럼을 정의하지 않아도 되므로 컬렉션에는 아무 데이터나 넣을 수 있다. 이러한 자유로움이 몽고디비의 장점이다. 단, 무엇이 들어올지 모르는 것은 단점이다.
기본적으로 몽고디비는 자바스크립트 문법을 사용해서 자바스크립트의 자료형을 따르지만 추가적인 몇 가지 자료형이 더 있다.
> db.컬렉션명.save(다큐먼트) # 다큐먼트를 생성할 수 있음.
> db.users.save({ name: "nero", age: 32, married: true,
comment: "안녕하세요. zero 친구 nero입니다.", createdAt: new Date() });
WriteResult({"nInserted": 1}) # 성공적으로 새로운 다큐먼트가 삽입되었음을 나타내는 메시지가 출력됨
8.5.2 Read(조회)
컬렉션 내 모든 다큐먼트 조회
> db.컬렉션명.find({});
특정 필드만 조회
> db.컬렉션명.find({}, {_id:0, name:1, married: 1});
# 조회할 필드에만 true 를 의미하는 1을 넣고, 조회하지 않는 필드에는 false를 의미하는 0을 넣음
$gt 특수 속성 사용
> db.users.find({ age: {$gt: 30}, married: true}, {_id:0, name: 1, age: 1});
# age가 30초과이고 married가 true 인 다큐먼트의 이름과 나이를 조회
$gt는 시퀄라이즈의 쿼리와 비슷하다.
몽고디비는 자바스크립트 객체를 사용해 명령어 쿼리를 생성해야 하므로 $gt와 같은 특수한 연산자가 사용된다.
자주 쓰이는 연산자:
몽고디비 $or 연산
> db.users.find({ $or: [{ age: {$gt: 30}}, {married: false}]}, {_id: 0, name: 1, age: 1});
{ "name" : "zero", "age" : 24 }
{ "name" : "nero", "age" : 32 }
# age가 30초과 이거나 married가 false dls 다큐먼트 조회
정렬
> db.users.find({}, {_id: 0, name: 1, age: 1}).sort({age: -1})
# users라는 컬렉션에서 age 값을 기준으로 내림차순 정렬. -1은 내림차순, 1은 오름차순.
조회할 다큐먼트 개수 설정 (limt 메서드 사용)
> db.users.find({}, {_id: 0, name: 1, age: 1}).sort({ age: -1 }).limit(1)
다큐먼트 개수를 설정하면서 몇 개를 건너뛸지 설장할 수 있다.
> db.users.find({}, {_id: 0, name: 1, age: 1 }).sort({ age: -1}).limit(1).skip(1)
8.5.3 Update(수정)
특정 필드 수정하기
> db.users.update({ name: 'nero' }, { $set: { comment: '안녕하세요. 수정한 필드입니다.' } });
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
# $set 연산자를 사용해서 수정하고,
# 성공했다면 첫 번째 객체에 해당하는 다큐먼트 수(nMatched)와 수정된 다큐먼트 수(nModified)가 나옴
8.5.4 Delete(삭제)
데이터 삭제
> db.users.remove({ name: 'nero' })
WriteResult({ 'nRemoved' : 1 })
# 삭제 성공시 삭제된 개수가 반환됨
8-6 몽구스 사용하기


MySQL에 시퀄라이즈가 있다면 몽고디비에는 몽구스가 있다.
*시퀄라이즈: ORM(Object-Relational Mapping) 도구
몽고디비는 릴레이션이 아니라 다큐먼트를 사용하므로 ORM이 아니라 ODM이다.
*릴레이션: 관계형 데이터베이스(RDBMS)에서 데이터를 저장하고 표현하는 기본 단위
몽고디비가 자바스크립트 객체와 매핑하는 이유는 몽고디비에 없어서 불편한 기능들을 몽구스가 보완하기 때문이다.
스키마 라는 것이 생겨, 몽고디비는 테이블없이 자유롭게 데이터를 넣을 수 있지만 자유로움이 불편함을 초래한다. 예를 들어 잘못된 자료형의 데이터를 넣었을 때, 다른 다큐먼트에 없는 필드의 데이터를 넣을 수도 있다.
몽구스는 몽고디비에 데이터를 넣기 전에 노드 서버 단에서 데이터를 한 번 필터링 하는 역할을 한다.
MySQL에 있는 JOIN 기능을 populate라는 메서드로 어느 정도 보완한다. 따라서 관계가 있는 데이터를 쉽게 가져올 수 있다. 쿼리 한 번에 데이터를 합쳐서 가져오는 것은 아니지만 우리 직접 작업하지 않아도 돼, 편리하다.
ES2015 프로미스 문법과 강력하고 가독성이 높은 쿼리 빌더를 지원하는 것도 장점이다.
8.6.1 몽고디비 연결하기
주소형
mongodb://[username:password@]host[:port]/[database][?options]]
# [ ] 부분은 있어도 되고 없어도 됨
username, password 에는 몽고디비 계정 이름과 비밀번호를 넣는다.
host = localhost, port = 27017, 계정이 있는 database가 admin 이므로 주소는 mongodb://이름:비밀번호@localhost:27017/admin이 된다.
8.6.2 스키마 정의하기
몽구스 모듈에서 shema 생성자를 이용해 스키마를 만든다. 시퀄라이즈에서 모델을 정의하는 것과 비슷하다. 필드를 각각 정의한다. 몽구는 알아서 _id를 기본 키로 생성하므로 _id 필드는 적어줄 필요가 없다. 나머지 필드의 스펙만 입력한다. 몽구스 스키마에서 특이한 점은 String, Number, Date, Buffer, Boolean, Mixed, ObjectId, Array 를 값을 가질 수 있다는 점이다. 몽고디비의 자료형과 조금 다르며, 편의를 위해 종류 수를 줄여두었다.
예시로, 줄여진 종류는 다음과 같다.
# schemas/user.js : 몽구스 스키마를 만드는 코드
const mongoose = require('mongoose');
const { schema } = mongoose;
const userSchema = new Schema({
name: {
type: String,
required: true,
unique: true,
},
age: {
type: Number,
required: true,
},
married: {
type: Boolean,
required: true,
},
comment: String,
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model('User', userSchema);
컬렉션 이름 바꾸기
몽구스는 model 메서드의 첫 번째 인수로 컬렉션 이름을 만든다. 첫 번째 인수가 User 라면 첫 글자를 소문자로 만든 뒤 복수형으로 바꿔서 users 컬렉션을 생성한다. comment라면 comments 컬렉션이 된다.
이런 강제 개명이 싫다면 세번째 인수로 컬렉션 이름을 줄 수 있다.
mongoose.model('User', userSchema, 'user_table');
# 이제 users 컬렉션 대신 user_table 컬렉션이 생성된다.
8.6.3 쿼리 수행하기
# 주요 코드 routes/users.js
# GET /users와 POST /users 주소로 요청이 들어올 때의 라우터
const express = require('express');
const User = require('../schemas/user');
const Comment = require('../schemas/comment');
const router = express.Router();
router.route('/')
.get(async (req, res, next) => {
try {
const users = await User.find({});
res.json(users);
} catch (err) {
console.error(err);
next(err);
}
})
.post(async (req, res, next) => {
try {
const user = await User.create({
name: req.body.name,
age: req.body.age,
married: req.body.married,
});
console.log(user);
res.status(201).json(user);
} catch (err) {
console.error(err);
next(err);
}
});
router.get('/:id/comments', async (req, res, next) => {
try {
const comments = await Comment.find({ commenter: req.params.id })
.populate('commenter');
console.log(comments);
res.json(comments);
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
GET /users 주소로 요청이 들어오면 데이터베이스의 모든 사용자 데이터를 조회하여 JSON 형식으로 반환한다.
반면, POST /users 요청은 새로운 사용자 데이터를 등록할 때 사용된다. 이때, 모델.create 메서드를 사용하여 데이터를 저장하며, 이는 MongoDB의 save()와는 다른 Mongoose만의 메서드이다. Mongoose는 이 과정에서 미리 정의된 스키마에 부합하지 않는 데이터가 들어오면 자동으로 에러를 발생시켜 데이터의 무결성을 지킨다. _id 필드는 사용자가 따로 입력하지 않아도 Mongoose가 자동으로 기본 키로 생성해준다.
GET /users/:id/comments와 같은 라우터는 특정 사용자(:id)가 작성한 댓글 다큐먼트를 조회한다. 이 조회 과정에서 Mongoose의 특별한 기능인 populate 메서드가 사용된다. 먼저 댓글 다큐먼트를 조회하면, 해당 다큐먼트의 commenter 필드에는 댓글을 쓴 사용자의 ObjectId 값만 저장되어 있다. 이때 populate를 사용하면, Mongoose는 이 ObjectId를 기반으로 ref로 지정된 users 컬렉션에서 해당 ID를 가진 사용자 다큐먼트 전체를 자동으로 찾아와 합친다. 결과적으로, 댓글 다큐먼트의 commenter 필드는 단순한 ID가 아니라 사용자의 전체 정보가 담긴 다큐먼트로 치환되어 반환된다. 이는 관계형 데이터베이스의 JOIN과 유사한 역할을 하여 데이터를 효율적으로 연결해준다.
1. MySQL은 객체-관계 매핑 도구인 ORM(Object-Relational Mapping)을 사용하고, 다큐먼트를 사용하는 몽고디비에서 몽구스(Mongoose)는 ( )을 사용한다.
2. 관계형 데이터베이스(MySQL)의 '테이블'에 해당하는 몽고디비(MongoDB)의 기본 데이터 저장 단위 용어는 ( )이다.
3. 몽구스(Mongoose)에서 관계형 데이터베이스의 JOIN과 유사하게, ObjectId로 연결된 다른 컬렉션의 다큐먼트를 자동으로 불러와 합쳐주는 메서드는 ( )이다.
4. 몽고디비 셸에서 기존 다큐먼트의 특정 필드 값만 수정할 때, 해당 필드와 값을 지정하기 위해 사용하는 연산자는( )이다.
5. 몽고디비가 관계형 데이터베이스(SQL)의 '안정성, 일관성' 대신 가장 중요하게 여기는 두 가지 핵심 가치는 ( , )이다.
6. 현재 몽고디비 셸에서 사용 중인 데이터베이스가 무엇인지 확인하는 간단한 명령어를 작성하시오.
7. 몽고디비 셸에서 'users' 컬렉션에 저장된 다큐먼트 중, 'age' 필드 값이 30을 초과하는 모든 다큐먼트를 조회하기 위한 정확한 명령어를 작성하시오.
1. ODM (Object Data Modeling)
2. 컬렉션(Collection)
3. populate
4. $set
5. 확장성, 가용성
6. db
7. db.users.find({ age: {$gt: 30} })
출처 : 조현영, 『 Node.js 교과서 개정 3판』, 길벗(2022),
Corner Node.js 1
Editor : GYEOMGYOEM
| [Node.js 1팀] 10장. 웹 API 서버 만들기 (0) | 2025.12.19 |
|---|---|
| [Node.js 1팀] 9장. 익스프레스로 SNS 서비스 만들기 (1) | 2025.11.28 |
| [Node.js 1팀] 7장. MySQL (0) | 2025.11.14 |
| [Node.js 1팀] 5장. 패키지 매니저, 6장. 익스프레스 웹 서버 만들기 (0) | 2025.11.07 |
| [Node.js 1팀] 3장. 노드 기능, 4장. http 모듈로 서버 만들기 (0) | 2025.10.31 |