MongoDB란?
MongoDB
란 데이터를 저장하는 데이터베이스 시스템의 한 종류로, 전통적인 테이블-관계 기반의 RDBMS가 아닌 도큐먼트 지향 NoSQL 데이터베이스 시스템입니다.

MongoDB의 특징
-
동적 스키마
MongoDB
는 테이블 구조가 고정되어 있는 형태(정적 스키마)가 아니라 JSON 형태의 동적 스키마형 문서를 사용합니다. 몽고디비에서는 그것을 Binary JSON(JavaScript Object Notaion)이라고 부르며, 줄여서 BSON
이라고 부르기도 합니다.
-
키-값의 집합 문서
앞서 작성한 특징과 비슷한데, 몽고 DB의 문서는 키-값의 집합으로 되어 있기 때문에 자바스크립트의 객체 코드와도 비슷한 형태로 되어 있습니다. 그래서 들어가는 데이터에 따라서 구조가 변경됩니다.
MongoDB의 장점
-
퍼포먼스가 뛰어납니다.
- 기본적으로 읽기 및 쓰기 성능이 뛰어나기 때문에 많은 트래픽을 감당할 때 사용해도 퍼포먼스가 뛰어납니다. 실제로 RDB보다 수십배는 빠른 성능을 발휘한다고 합니다.
-
개발이 편리합니다.
- JSON 형태로 저장이 가능하기 때문에 직관적입니다.
MongoDB의 단점
-
조인이 없습니다.
- 조인이 없기 때문에 데이터 구조화를 할 필요가 있습니다.
(MongoDB 3.2 버전 부터 보조적인 JOIN 기능으로 $lookup을 지원하기는 합니다.)
외래키의 개념이 없으며 데이터 구조의 동적인 특성 때문에 몽고 DB의 데이터 모델링은역정규화(Denormalization)
로 흐르곤 합니다.
- 조인이 없기 때문에 데이터 구조화를 할 필요가 있습니다.
-
메모리에 의존적입니다.
- 데이터 갱신 시 바로 디스크에 쓰는 것이 아니라 논리적으로 메모리에 쓰고나서 일정 주기에 따라서 비동기식으로 쓰기 때문에 메모리에 의존적이며 때로는 데이터가 유실 될 가능성이 존재하기도 합니다. 메모리에 의존적이기 때문에 메모리 크기가 성능을 좌우합니다.
MongoDB는 언제 쓰는 것이 좋을까?
Humongous(거대한) Database를 줄인 MongoDB라는 이름에서도 알 수 있듯이 MongoDB는 방대한 데이터 읽기가 필요한 경우에 사용하기 적합합니다. 로그성 데이터를 저장하는 경우, null 필드가 많이 존재하는 경우, 압도적인 퍼포먼스가 필요한 경우 등에 사용하기 좋습니다.
✔️ RDB와 MongoDB 용어 비교
RDB와 MongoDB 용어를 비교하는 경우 아래와 같습니다.
RDB | MongoDB |
---|---|
Table | Collection |
Row | Document |
Column | Field |
Primary Key | Object_Id Field |
Relationship | Embedded & Link |
✔️ 연산자 정리
👉 비교연산자
operator | 설명 |
---|---|
$eq | 같음 (==) |
$gt | 초과 (>) |
$gte | 이상 (≥) |
$lt | 미만 (<) |
$lte | 이하 (≤) |
$ne | 같지 않음 (!=) |
$in | 전달한 배열 요소 중 하나 |
$nin | 배열 요소에 없거나 필드가 존재하지 않을 때 조회 |
👉 논리연산자
operator | 설명 |
---|---|
$or | 주어진 조건 중 하나라도 true인 경우 true 반환 |
$and | 모든 조건이 true 이면 true 반환 |
$not | 해당 조건이 false 이면 true 반환 |
$nor | 모든 조건이 false 이면 true 반환 |
✔️ 쿼리 정리
👉 documents 조회(find)
db.<collection 이름>.find()
입력 key&value 값을 가진 docs만 리턴
db.<collection 이름>.find({ "books" : "Gravity" })
views의 값이 30이하인 docs만 리턴
db.<collection 이름>.find({ "views" : {$lte:30} })
쿼리 결과에 보여줄 field지정
db.<collection 이름>.find({},{ "_id" : false, "title" : true })
comments의 name이라는 field의 value가 Charles인 docs만 출력
- $elemMatch : embedded doct 배열 쿼리시 사용
db.<collection 이름>.find({ "comments" : {$elemMatch : { "name" : "Charles" }}})
보기좋게 정렬: pretty()
db.cities.find({ name: "Minneapolis" }).pretty();
오름차순 & 내림차순 정렬: sort()
- name field를 내림차순으로 정렬하여 출력
db.<collection 이름>.find({},{ "name" : true }).sort({ "name" : -1 })
- id field를 내림차순으로 정리하고, name field를 오름차순으로 정렬하여 출력
db.<collection 이름>.find({},{ "name" : true }).sort({ "_id" : -1 , "name" : 1 })
5개 docs만 출력
db.<collection 이름>.find().limit(5)
2개를 건너뛰고 그 다음 docs를 출력
db.<collection 이름>.find().skip(2)
👉 데이터 업데이트
INSERT 하기
db.people.insert([
{ name: "Abet", age: 19 },
{ name: "Betty", age: 20 },
{ name: "Charlie", age: 23, skills: ["mongodb", "nodejs"] },
{ name: "David", age: 23, score: 20 },
]);
특정 field 업데이트 하기: $set
db.people.update({ name: "Abet" }, { $set: { age: 20 } }) >
WriteResult({ nMatched: 1, nUpserted: 0, nModified: 1 });
특정 field 제거하기: $unset
db.people.update({ name: "David" }, { $unset: { score: 1 } }) >
WriteResult({ nMatched: 1, nUpserted: 0, nModified: 1 });
field가 있으면 수정, 없으면 새로 추가하기 : upsert:true
db.people.update({ name: "Elly" }, { name: "Elly", age: 17 }, { upsert: true });
WriteResult({
nMatched: 0,
nUpserted: 1,
nModified: 0,
_id: ObjectId("56c893ffc694e4e7c8594240"),
});
특정 조건에 맞는 field 한꺼번에 수정하기: multi:true
db.people.update(
{ age: { $lte: 20 } },
{ $set: { score: 10 } },
{ multi: true }
) > WriteResult({ nMatched: 3, nUpserted: 0, nModified: 0 });
skills 배열에 새로운 값 추가하기: $push
db.people.update({ name: "Charlie" }, { $push: { skills: "angularjs" } });
WriteResult({ nMatched: 1, nUpserted: 0, nModified: 1 });
skills 배열에 여러 값 추가하고 오름차순으로 정렬하기: $each, $sort
db.people.update(
{ name: "Charlie" },
{
$push: {
skills: {
$each: ["c++", "java"],
$sort: 1,
},
},
}
) > WriteResult({ nMatched: 1, nUpserted: 0, nModified: 1 });
skills 배열에 하나의 요소 제거: $pull
db.people.update({ name: "Charlie" }, { $pull: { skills: "mongodb" } });
👉 커스텀 인덱스 추가
이미 존재하는 collection 에 추가할 경우
db.products.createIndex(
{ item: 1, quantity: -1 },
{ name: "query for inventory" }
);
인덱스 종류 쿼리
db.cities.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.cities"
},
{
"v" : 2,
"key" : {
"_id" : 1,
"checkins" : -1
},
"name" : "_id_1_checkins_-1",
"background" : true,
"ns" : "test.cities"
},
{
"v" : 2,
"key" : {
"geolocation" : "2dsphere",
"_id" : 1,
"checkins" : -1
},
"name" : "geolocation_2dsphere__id_1_checkins_-1",
"ns" : "test.cities",
"background" : true,
"2dsphereIndexVersion" : 3
}
// ... 생략됨
new schema, field 레벨 에서 추가
var animalSchema = new Schema({
name: String,
type: String,
tags: { type: [String], index: true }, // animal의 tag를 인덱스로 지정
});
new schema, compound index는 항상 schema 레벨에서 추가하기
animalSchema.index({ name: 1, type: -1 }); // schema level