본문 바로가기

BackEnd/MongoDB

[MongoDB] 몽고DB 이해하기

 

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>