::: IT인터넷 :::

MongoDB의 Document 사용하기 (CRUD)

곰탱이푸우 2022. 8. 8. 08:20
Docker를 이용하여 MongoDB를 설정했다면 실제 명령어를 사용해 볼 필요가 있다.
Document의 생성, 읽기, 수정, 삭제에 대해 알아본다.
 
MongoDB의 Database와 Collection을 사용하는 방법은 아래 포스팅을 참고한다.
MongoDB의 Document 구조와 관계 패턴은 아래 포스팅을 참고한다.
MongoDB의 구조와 특징은 아래 포스팅을 참고한다.
 

준비 사항

DB 명령어는 MongoDB Docker 컨테이너 내부에서 mongosh를 실행해서 진행한다.
 
Docker를 이용한 MongoDB 설정과 mongosh 실행 방법은 아래 포스팅을 참고한다.

Document 관리

Document 개념

RDBMS의 Row와 유사한 개념으로 다음과 같이 키 (Key)와 값 (Value)으로 구성 된다.
키와 값의 쌍은 여러 개가 있을 수 있고, 값이 없으면 null로 처리한다.
// { "key" : "value" }
// Key (또는 Value) - RDBMS의 컬럼 역할
// Value - RDBMS의 레코드 역할

{ "name" : "Joe" }
{ "name" : "Joe", "dept" : "Sales" }
{ "name" : "Joe", "dept" : "Sales", "age' : null }
 
키와 값은 데이터 타입과 대소문자를 구별한다. 다음 Document는 모두 다르다.
{"count" : 5} // count의 데이터 형이 int
{"count" : "5"} // count의 데이터 형이 String
{"Count" : "5"} // count의 알파벳이 대문자로 시작
 
또한 단일 Document에서 키는 중복 될 수 없다. 필요한 경우 배열로 처리해야 한다.
// Key가 중복 된 경우
{ "name" : "Joe", "dept" : "Sales", "dept" : "Marketing" }

// 표현 방법
{ "name" : "Joe", "dept" : ["Sales", "Marketing"] }

 

 

Data Type

MongoDB의 키는 문자열 타입으로 지정 된다.
 
값 부분은 다양한 포맷을 지원하며 타입 추론을 지원한다.
물론 데이터에 직접 명시해도 되지만 꼭 필요한 경우가 아니라면 MongoDB의 타입 추론을 따르는 것을 권장한다.
 
또한 값 부분에 JavaScript의 코드와 정규식 사용이 가능하다.
자주 사용하는 데이터 타입은 다음과 같다.
구분
예제 코드
내용
null
{ "x" : null }
특정 필드의 값이 존재하지 않는 경우
Boolean
{ "x" : true }
참(true)과 거짓(false)
Integer
{ "x" : 10 }
정수형 숫자
Double
{ "x" : 3.14 }
실수형 숫자 (64비트 부동소수점 사용)
String
{ "x" : "test" }
문자열
Date
{ "x" : new Date() }
날짜 (64비트 정수)
Regular Expression
{ "x" : /test/i }
정규 표현식 (JavaScript의 정규표현식 문법 사용)
Array
{ "x" : ["a", "b", "c"] }
배열 (리스트)
Embedded Document
{"x" : {"name" : "Joe"}}
임베디드 Document (계층 구조 표현 가능)
ObjectId
{ "x" : ObejctId() }
Document의 고유 식별자
JavaScript
{ "x" : function() {...} }
JavaScript 코드
 
자세한 내용은 아래 기술 문서를 참고한다.
ObjectId는 아래 포스팅의 ObjectId 항목을 참고한다.
 

Document 추가

Document를 추가하기 위해서는 사용할 Database를 지정해야 한다.
> use Database이름
switched to db Database이름
Database이름>
 
예전에는 insert라는 단일 메소드를 제공했지만 3.2 버전부터 Deprecated 되었고 다른 메소드를 제공한다.
상황에 따라 insertOne, insertMany, bulkWrite 메소드를 선택해서 사용한다.
 
단일 추가
아래와 같이 단일 Document를 추가할때에는 insertOne 메소드를 사용한다.
전달 인자로 단일 Document가 전달 된다.
> db.publisher.insertOne( {"name": "doremi", "tel": "02-123-4567"} )
{
  acknowledged: true,
  insertedId: ObjectId("626b93f465644e076f78f82d")
}
 
자세한 내용은 아래 기술 문서를 참고한다.
여러개 추가
아래와 같이 여러 개의 Document를 추가할때에는 insertMany 메소드를 사용한다.
전달 인자로 여러 개의 Document가 배열 형태로 전달 된다.
> db.products.insertMany( [
      { item: "card", qty: 15 },
      { item: "envelope", qty: 20 },
      { item: "stamps" , qty: 30 }
  ] )

{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId("626b96c065644e076f78f831"),
    '1': ObjectId("626b96c065644e076f78f832"),
    '2': ObjectId("626b96c065644e076f78f833")
  }
}
 
자세한 내용은 아래 기술 문서를 참고한다.
 

Document 조회

특정 Collection의 Document 목록을 확인할 때 사용한다.
RDBMS에서는 SELECT 구문을 사용했지만 MongoDB에서는 find와 findOne 메소드를 사용한다.
 
자세한 내용은 아래 기술 문서를 참고한다.
아래 예제 외에도 find와 findOne 메소드를 활용한 다양한 메소드를 제공한다.
  • findAndModify
  • findAndUpdate
  • findOneAndDelete
  • findOneAndReplace
  • findOneAndUpdate
해당 메소드들은 MongoDB의 기술 문서를 참고한다.
 
전체 조회
전달 인자 없이 find 메소드를 사용하면 해당 Collection의 전체 Document를 보여준다.
다음과 같이 사용한다.
# 기본 형식
> db.Collection이름.find()

# 실제 예제
> db.products.find()
[
  {
    _id: ObjectId("626b96c065644e076f78f831"),
    item: 'card',
    qty: 15 },
  {
    _id: ObjectId("626b96c065644e076f78f832"),
    item: 'envelope',
    qty: 20
  },
  {
    _id: ObjectId("626b96c065644e076f78f833"),
    item: 'stamps',
    qty: 30
  }
]
 
 
일부 조회
find 메소드에 전달 인자를 Document 형식의 검색 조건을 지정하면 일부만 조회할 수 있다.
MongoDB 내부에서 필터링 연산을 수행한다.
 
기본적으로 다음 형식을 가진다.
# 특정 값 검색
> db.Collection이름.find( { 필드명: 값 } )

# 연산자 검색
> db.Collection이름.find( { 필드명: { 연산자: 값 }, ... }, ... )
 
MongoDB 연산자 목록은 아래 문서를 참고한다.
다음과 같이 사용할 수 있다.
# 특정 값 검색
> db.bios.find( { "name.last": "Hopper" } )

# 범위 검색
> db.bios.find( { birth: { $gt: new Date('1950-01-01') } } )
> db.bios.find( { birth: { $gt: new Date('1940-01-01'), $lt: new Date('1960-01-01') } } )

# 여러 조건 쿼리
> db.bios.find( {
      birth: { $gt: new Date('1920-01-01') },
      death: { $exists: false }
  } )
 
그 외에도 다양한 조건의 쿼리를 수행할 수 있다.
아래 기술 문서를 참고한다.
단일 조회
전달 인자 없이 findOne 메소드를 사용하면 해당 Collection에서 조회한 첫 번째 Document를 보여준다.
다음과 같이 사용한다.
# 기본 형식
> db.Collection이름.findOne()
 
특정 조건에 해당하는 첫 번째 Document만 조회하려면 검색 조건을 지정한다.
# 기본 형식
> db.Collection이름.findOne( { 필드명: 값 } )

# 연산자 검색
> db.Collection이름.findOne( { 필드명: { 연산자: 값 }, ... } )
 
그 외에도 다양한 조건의 쿼리를 수행할 수 있다.
아래 기술 문서를 참고한다.
 

Document 수정

특정 Collection의 Document 중 일부를 수정할 때 사용한다.
RDBMS에서는 UPDATE 구문을 사용했지만 MongoDB에서는 updateOne과 updateMany 메소드를 사용한다.
기존에는 update 메소드를 사용했지만 Deprecated 되었다.
 
자세한 내용은 아래 기술 문서를 참고한다.
단일 수정
updateOne 메소드를 사용하면 해당 Collection에서 조회한 첫 번째 Document를 수정한다.
다음과 같이 사용한다.
# 기본 형식
> db.Collection이름.updateOne( { 검색조건 }, { Update연산자 : { 수정할필드:수정할값 } } )
 
검색 조건은 은 Document  형태로 전달 되어야 한다.
검색 조건은 다음과 같이 지정한다.
# 단일 값 검색
> db.Collection이름.updateOne( { 필드명: 값 }, { Update연산자 : { 수정할값 } } )

# 예제
> db.restaurant.updateOne(
      { "name" : "Central Perk Cafe" },
      { $set: { "violations" : 3 } }
  )


# 연산자 검색
> db.Collection이름.updateOne( { 필드명: { 연산자: 값 }, ... }, { Update연산자 : { 수정할값 } } )

# 예제
> db.restaurant.updateOne( 
    { violations: { $gt: 4 } },
    { $set: { "Review" : true } }
  )
 
Update 연산자는 $set (값 설정), $unset (값 해제), $inc (증가), $dec (감소) 등 다양하다.
Update 연산자의 자세한 내용은 아래 기술 문서를 참고한다.
UpdateOne 메소드는 아래 기술 문서를 참고한다.
다중 수정
updateMany 메소드를 사용하면 해당 Collection에서 조회한 여러 Document들을 한번에 수정할 수 있다.
다음과 같이 사용한다.
# 기본 형식
> db.Collection이름.updateMany( { 검색조건 }, { Update연산자 : { 수정할필드:수정할값 } } )

# 예제
> db.restaurant.updateMany(
    { violations: { $gt: 4 } },
    { $set: { "Review" : true } }
  )
 
검색 조건, Update 연산자, 수정할 값에 대한 세부 내용은 UpdateOne 메소드와 동일하다.
검색 결과가 너무 많을 경우 I/O가 많아져 성능에 영향을 줄 수 있다.
 
UpdateMany 메소드는 아래 기술 문서를 참고한다.

Documnet 삭제

특정 Collection의 Document 중 일부를 삭제할 때 사용한다.
RDBMS에서는 DELETE 구문을 사용했지만 MongoDB에서는 deleteOne과 deleteMany 메소드를 사용한다.
기존에는 remove 메소드를 사용했지만 Deprecated 되었다.
 
자세한 내용은 아래 기술 문서를 참고한다.
단일 삭제
deleteOne 메소드를 사용하면 해당 Collection에서 조회한 첫 번째 Document를 삭제한다.
다음과 같이 지정한다.
# 단일 조건으로 삭제 대상 선정
> db.Collection이름.deleteOne( { 필드명: 값 } )

# 예제
> db.orders.deleteOne( { "_id" : ObjectId("563237a41a4d68582c2509da") } )


# 연산자로 삭제 대상 선정
> db.Collection이름.deleteOne( { 필드명: { 연산자: 값 }, ... } )

# 예제
> db.orders.deleteOne( { "expiryts" : { $lt: ISODate("2015-11-01T12:40:15Z") } } )
 
MongoDB 연산자 목록은 아래 문서를 참고한다.
deleteOne 메소드는 아래 기술 문서를 참고한다.
다중 삭제
deleteMany 메소드를 사용하면 해당 Collection에서 조회한 여러 Document들을 한번에 삭제할 수 있다.
다음과 같이 사용한다.
# 단일 조건으로 삭제 대상 선정
> db.Collection이름.deleteMany( { 필드명: 값 } )

# 예제
> db.orders.deleteMany( { "client" : "Crude Traders Inc." } )


# 연산자로 삭제 대상 선정
> db.Collection이름.deleteMany( { 필드명: { 연산자: 값 }, ... } )

# 예제
> db.orders.deleteMany( { "stock" : "Brent Crude Futures", "limit" : { $gt : 48.88 } } )
 
UpdateMany 메소드는 아래 기술 문서를 참고한다.
 

대용량 작업

BulkWrite 메소드를 이용하면 MongoDB의 데이터를 변경하는 여러 명령들을 한번에 실행할 수 있다.
실행 가능한 명령은 다음과 같다.
  • INSERT - insertOne
  • UPDATE - updateOne, updateMany, replaceOne
  • DELETE - deleteOne, deleteMany
 
INSERT, UPDATE, DELETE 등의 명령어를 조합해서 사용 가능하다.
다음과 같이 사용한다.
# 기본 형식
> db.Collection이름.bulkWrite(
    [
        { insertOne : { "document" : { "key": "value", ... } } },
        { updateOne :  // 또는 updateMany
            { "filter" : { 검색조건 },
            { "update" : { Update연산자: { 수정할필드:수정할값 } } }
        },
        { replaceOne : {
            { "filter" : { 검색조건 },
            { "update" : { Update연산자: { 수정할필드:수정할값 } } }
        },
        { deleteOne :  // 또는 deleteMany
            { "filter" : { 검색조건 },
            { "update" : { Update연산자: { 수정할필드:수정할값 } } } 
        }
    ]
)
 
예제 코드는 다음과 같다.
> db.characters.bulkWrite(
    [
        { insertOne :
            { "document" : { "_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4 } }
        },
        { insertOne :
            { "document" : { "_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3 } }
        },
        { updateOne : {
            "filter" : { "char" : "Eldon" },
            "update" : { $set : { "status" : "Critical Injury" } }
        } },
        { deleteOne : { "filter" : { "char" : "Brisbane" } } },
        { replaceOne : {
            "filter" : { "char" : "Meldane" },
            "replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }
        } }
    ]
)

{
    "acknowledged" : true,
    "deletedCount" : 0,
    "insertedCount" : 2,
    "matchedCount" : 0,
    "upsertedCount" : 0,
    "insertedIds" : {
        "0" : 4,
        "1" : 5
    },
    "upsertedIds" : { }
}
 
 
bulkWrite 메소드 실행 중 오류가 발생하면 BulkWriteError가 반환된다.
기본적으로 Roll-back은 수행하지 않고 ordered 옵션의 사용 여부에 따라 처리 방식이 조금 다르다.
  • true인 경우 순서대로 처리하며 중간에 오류가 발생하면 성공한 부분은 유지하고 남은 작업은 포기한다.
  • false인 경우 병렬로 처리하며 오류가 발생한 부분만 제외하고 나머지는 모두 처리한다.
ordered 옵션은 병렬 처리 여부에 대한 옵션으로 이해하면 좋다.
 
bulkWrite 메소드는 아래 기술 문서를 참고한다.