MongoDB란?
MongoDB는 문서 지향적인 NoSQL 데이터베이스로, 대량의 비정형 데이터를 저장하고 처리하는 데 사용된다. 여기서 문서 지향적(document-oriented)이란 비정형 데이터를 저장하고 관리하기 위해 문서(Document)라는 개념을 중심으로 데이터를 구성한다.
관계형 데이터베이스의 경우 SQL이라 부르는 질의 언어를 사용하지만, MongoDB는 자바스크립트와 같은 전혀 다른 질의어를 사용한다. 즉 사용자 측면에서는 자바스크립트를 알면 다른 언어를 배울 필요가 없는 장점이 있다.
앞으로 사용할 몽고셸은 몽고디비와 함께 설치해야 하며 터미널, powershell을 통해 접근할 수 있다.
> mongosh
DB 목록ㅇ 조회/생성/삭제하기
구분 | 명령어 | 설명 |
조회 | show dbs | DB목록 조회하기 |
생성/조회 | use user | local이라는 DB가 존재유무에 따라 선택/생성이 정해진다. |
조회 | db | 현재 사용 중인 DB 이름을 조회한다. |
데이터 삽입 | db.user.insertOne({ name: 'Jack'}) | 새로운DB에실제 데이터를삽입하며 이 과정에서 디비가 물리적으로 생성된다. |
삭제 | > use user > db.dropDatabase() |
삭제할 DB를 선택 후 드랍명령어를 수행해 선택한 디비를 삭제한다. |
컬렉션과 문서
RDBMS에서는 데이터들을 여러 개로 나누어 각각의 테이블(table)에 저장하며 저장되는 한 건의 데이터를 레코드(record)라고 한다. 즉, RDBMS에서 테이블이란 테이블에 정의된 스키마에 맞춰 작성된 레코드 저장소이다.
몽고DB는 스키마가 없는 저장소를 갖고 있으며 이를 컬렉션(collection)이라고 하며, 컬렉션에 저장되는 한 건의 데이터를 문서(document)라고 한다.
컬렉션 조회/생성/삭제하기
구분 | 명령어 | 설명 |
생성 | > use mydb > db.createCollection("user", {}) |
컬렉션 생성시 사용하는 명령어이다. "user"라는 읾의 컬렉션을 기본 옵션으로 생성한 예이며 옵션은 {} 여기에 넣을 수 있다. |
조회 | > db.getCollectionNames() | 현재 사용중인 DB의 모든 컬렉션을 보기 위해 사용한다. |
삭제 | > db.user.drop() | 생성한 user 컬렉션을 삭제한다. |
_id 필드와 ObjectId 타입
몽고DB 문서는 _id라는 특별한 이름의 필드(field)를 가지는데, 이 필드는 문서가 DB에 저장될 때 자동으로 만들어진다. _id 필드와 UUID는 개념적으로는 같지만, - 기호 없이 ObjectId("문자열") 형태로 사용해야 한다.
mydb> db.user.find({})
[
{ _id: ObjectId('67774c87cbc396ee1d4eeb86'), name: 'Jac', age: 32 },
{ _id: ObjectId('67774c8fcbc396ee1d4eeb87'), name: 'Tom', age: 33 }
]
몽고DB는 ObjectId("67774c87cbc396ee1d4eeb86") 부분을 다음처럼 생성하고 해석한다.
- 4바이트 타임스탬프, 67774c87
- 5바이트 랜덤 요소, cbc396ee1d
- 3바이트 카운터, 4eeb86
컬렉션의 CRUD 메서드
몽고DB는 CRUD 메서드를 제공한다. 문서 1건이 대상인 메서드는 '이름One' 형태의 'One'이란 접미사를 사용하고 여러 문서를 대상으로 하는 메서드는 '이름Many' 형태의 'Many'란 접미사를 사용한다.
- 생성(create operations) : insertOne, insertMany
- 검색(read opertations) : findOne, findMany
- 수정(update operations) : updateOne, updateMany, findOneAndUpdate
- 삭제(delete operations) : deleteOne, deleteMany
문서 생성/검색 메서드 사용하기
앞서 본 insertOne과 insertMany를 통해 단건 문서추가와 복건 문서 추가를 수행한다.
mydb> db.user.insertOne({name:'Jac',age: 32})
{
acknowledged: true,
insertedId: ObjectId('67776308cbc396ee1d4eeb88')
}
mydb> db.user.insertMany([{name:'Tom',age: 20}, {name:'Kim', age:39}])
{
acknowledged: true,
insertedIds: {
'0': ObjectId('67776385cbc396ee1d4eeb89'),
'1': ObjectId('67776385cbc396ee1d4eeb8a')
}
}
등록된 데이터의를 조회하기 위해 findOne과 find를 통해 문서 조회를 수행한다. findOne, find의 메서드 중괄호 안에는 조건을 넣어 원하는 데이터를 추출할 수 있다.
mydb> db.user.findOne({}) // ({name:'Jac')} : 이름이 Jac인 대상을 조회한다.
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'Jac', age: 32 }
mydb> db.user.find({}) // ({age: {$gt: 15}}) : 나이가 15살보다 큰 사용자를 조회한다.
[
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'Jac', age: 32 },
{ _id: ObjectId('67776385cbc396ee1d4eeb89'), name: 'Tom', age: 20 },
{ _id: ObjectId('67776385cbc396ee1d4eeb8a'), name: 'Kim', age: 39 }
]
몽고DB에서 연산자란?
몽고DB에서는 $gt처럼 달러 기호를 접두사로 사용하는 키워드를 연산자라고 하며 검색 연산자의 사용법은 아래와 같다.
{ 필드_이름1: { 검색_연산자1: 값1 }, 필드_이름2: { 검색_연산자2: 값2}, ...}
비교 연산자 알아보기
비교 연산자란 일반적으로 프로그래밍 언어에서 두 값을 사용할 때 사용하는 '=', '>', '<' 기호와 이들을 조합을 의미한다.
연산자 이름 | 의미 | 연산자 이름 | 의미 | 연산자 이름 | 의미 |
$eq | 필드_값 == 값 | $gt | 필드_값 > 값 | $lt | 필드_값 < 값 |
$ne | 필드_값 != 값 | $gte | 필드_값 >= 값 | $lte | 필드_값 <= 값 |
mydb> db.user.find({name: {$eq: 'Kim'}, age: {$gt: 30}})
[ { _id: ObjectId('67776385cbc396ee1d4eeb8a'), name: 'Kim', age: 39 } ]
이 외에도 여러 값 중에 일치/불일치 하는 값을 가지는 문서를 찾아야 하는 경우가 있어 $in과 $nin을 사용한다.
연산자 이름 | 의미 |
$in | { 필드명: { $in: [값1, 값2, ...] } } 형태로 사용되며 하나라도 일치하면 해당 문서를 반환한다. |
$nin | { 필드명: {$nin: [값1, 값2, ...] } } 형태로 사용되며 전부 일치하지 않는 해당 문서를 반환한다. |
mydb> db.user.find({age: {$in:[20,32]}})
[
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'Jac', age: 32 },
{ _id: ObjectId('67776385cbc396ee1d4eeb89'), name: 'Tom', age: 20 }
]
mydb> db.user.find({age: {$nin:[20,32]}})
[ { _id: ObjectId('67776385cbc396ee1d4eeb8a'), name: 'Kim', age: 39 } ]
논리 연산자 알아보기
논리 연산자는 프로그래밍 언어에서 &&, ||, ! 등의 논리 조건을 표현할 때와 유사하다.
연산자 이름 | 의미 |
$and | 모든 검색 조건을 모두 만족하는(AND) 문서를 찾을 때 사용 |
$not | 모든 검색 조건을 모두 만족하지 않는(NOT) 문서를 찾을 때 사용 |
$or | 모든 검색 조건 중 하나라도 만족하는(OR) 문서를 찾을 때 사용 |
$nor | 모든 검색 조건 중 하나라도 만족하지 않는(NOR) 문서를 찾을 때 사용한다. |
논리 연산자는 다음처럼 값 부분을 검색 조건을 가진 객체의 배열로 설정해 사용한다.
// { 논리_연산자: [ { 검색_조건1 }, { 검색_조건2 }, ... { 검색_조건N } ] }
mydb> db.user.find({$and : [{name: {$in:['Jac','Tom']}},{age: {$gt:20}}]})
[ { _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'Jac', age: 32 } ]
$regex 정규식 연산자
자바스크립트는 RegEx라는 이름의 클래스로 정규 표현식(regular expression) 기능을 제공한다. 정규식은 "이름이 J로 시작하는 것" 처럼 와일드카드(wildcard) 검색을 할 때 유용한 기능이다.
// 둘다 동일한 정규식 문법이다.
const re = new RegEx(정규식)
const re = /정규식/
mydb> db.user.find({name: { $regex: /^J.*$/}})
[
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'Jac', age: 32 },
{ _id: ObjectId('67776da2cbc396ee1d4eeb8b'), name: 'Jane', age: 18 }
]
필드 업데이트 연산자 사용하기
컬렉션의 update관련 메서드는 문서의 특정 필드값을 다른 값으로 바꾸는 데 사용된다.
연산자 이름 | 용도 |
$set | { $set: { 필드_이름: 값, ...} } 형태로 문서의 특정 필드 값을 변경할 때 사용 |
$inc | { $inc: { 필드_이름: 값, ... } } 형태로 문서의 숫자 타입 필드값을 증가 시킬 때 사용 |
$dec | { $dec: { 필드_이름: 값, ... } } 형태로 문서의 숫자 타입 필드값을 감소 시킬 때 사용 |
문서 수정 메서드 사용하기
updateOne, updateMany, findOneAndUpdate 등은 컬렉션에 저장된 문서 필드값을 수정하는 메서드이며 사용법은 아래와 같고 옵션 부분은 생략이 가능하다.
db.컬렉션_이름.updateOne(검색_조건_객체, 필드_업데이트_연산자_객체, 옵션)
db.컬렉션_이름.updateMany(검색_조건_객체, 필드_업데이트_연산자_객체, 옵션)
db.컬렉션_이름.findOneAndUpdate(검색_조건_객체, 필드_업데이트_연산자_객체, 옵션)
아래와 같이 updateOne의 경우 검색 조건에 맞는 문서가 1건이고 변경된 데이터도 1건이기 때문에 matchedCount, modifiedCount가 1이다. 즉 updateOne은 1건만 업데이트가 되며 결과로 'Jane'은 수정이 안된 것을 확인할 수 있다.
mydb> db.user.updateOne({name: { $regex: /^J.*$/} }, {$set: {name: 'John'}, $inc: {age:10} } )
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
mydb> db.user.find({name: { $regex: /^J.*$/}})
[
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'John', age: 42 },
{ _id: ObjectId('67776da2cbc396ee1d4eeb8b'), name: 'Jane', age: 18 }
]
아래와 같이 updateMany를 사용하면 모든 문서의 값을 변경 시킬 수 있다. 결과적으로 matchedCount와 modifiedCount가 2라는 값을 가진 것을 확인할 수 있으며 두 값들의 나이가 모두 10씩 증가한 것을 확인할 수 있다.
mydb> db.user.updateMany({name: { $regex: /^J.*$/} }, {$inc: {age:10} } )
{
acknowledged: true,
insertedId: null,
matchedCount: 2,
modifiedCount: 2,
upsertedCount: 0
}
mydb> db.user.find({name: { $regex: /^J.*$/}})
[
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'John', age: 52 },
{ _id: ObjectId('67776da2cbc396ee1d4eeb8b'), name: 'Jane', age: 28 }
findOneAndUpdate 메서드는 returnNewdocument 속성값이 true이면 결과로 변경된 값을 반환하며, false일 경우 변경되기 전의 값을 반환한다.
mydb> db.user.findOneAndUpdate({name: 'John'}, {$set: {age: 55}})
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'John', age: 52 }
mydb> db.user.find({name: {$eq : 'John'}})
[
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'John', age: 55 }
]
mydb> db.user.findOneAndUpdate({name: 'John'}, {$set: {age: 30}}, { returnNewDocument: true})
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'John', age: 30 }
mydb> db.user.find({name: {$eq : 'John'}})
[
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'John', age: 30 }
]
문서 삭제 메서드 사용하기
컬렉션에 담긴 문서를 삭제할 때는 deleteOne, deleteMany 메서드를 사용해 삭제할 수 있으며 옵션은 생략 가능하다.
db.컬렉션_이름.deleteOne(검색_조건_객체, 옵션)
db.컬렉션_이름.deleteMany(검색_조건_객체, 옵션)
mydb> db.user.find({name: { $regex: /^J.*$/}})
[
{ _id: ObjectId('67776308cbc396ee1d4eeb88'), name: 'John', age: 30 },
{ _id: ObjectId('67776da2cbc396ee1d4eeb8b'), name: 'Jane', age: 28 },
{ _id: ObjectId('677778afcbc396ee1d4eeb8c'), name: 'Jack', age: 30 }
]
// 1건만 삭제
mydb> db.user.deleteOne({name: { $regex: /^J.*$/}})
{ acknowledged: true, deletedCount: 1 }
mydb> db.user.find({name: { $regex: /^J.*$/}})
[
{ _id: ObjectId('67776da2cbc396ee1d4eeb8b'), name: 'Jane', age: 28 },
{ _id: ObjectId('677778afcbc396ee1d4eeb8c'), name: 'Jack', age: 30 }
]
// 모두 삭제
mydb> db.user.deleteMany({name: { $regex: /^J.*$/}})
{ acknowledged: true, deletedCount: 2 }
mydb> db.user.find({name: { $regex: /^J.*$/}})
mydb>