MongoDB 용어와 데이터처리

송윤주·2024년 4월 17일
0

데이터베이스

목록 보기
2/13

내가 아직 다뤄본 적이 없는 nosql 데이터베이스 시스템에 대해서 정리해보고자 이 글을 작성한다. (사진은 테이블이 없는 몽고db의 특징 ㅋㅋ)

용어 비교

위처럼 sql과 몽고db의 사용용어가 다르다.
컬렉션의 경우 문서들의 집합이며 각 문서는 필드와 값의 쌍으로 구성된다. 이때 필드는 특정 값이나 데이터 유형을 포함한다. 그리고 mongodb에서 기본 키 역할을 하는 것은 ObjectID 이며 mongodb에서 자동으로 생성되는 고유한 식별자이다.

기본키 할당

여기서 기본키에 대해서 좀 더 자세히 설명하자면 아래와 같다.

  1. ObjectId:

    • ObjectId는 몽고DB에서 기본적으로 사용되는 고유한 식별자이다.
    • 12바이트의 16진수로 표현되며, 일반적으로 24자리 문자열로 표현된다.
    • ObjectId는 BSON(Object Notation) 데이터 형식에서 사용되며, 다양한 클라이언트 라이브러리와 몽고DB 셸에서 자동으로 생성된다.
    • 일반적으로 새 문서를 삽입할 때 몽고DB가 자동으로 _id 필드에 ObjectId를 할당한다.
    • 예시:
      66024d63abe17c97531a9d35 이런식으로 발급되는데 이는 이렇게 슬라이싱 된다.
      66024d63 / abe17c / 9753 / 1a9d35
      타임스탬프(8) / 서버ID(6) / 프로세서ID(4) / 로컬 카운터(6)
  2. _id 필드:

    • _id 필드는 몽고DB 문서의 기본 키(primary key) 역할을 한다.
    • 문서의 고유성을 보장하기 위해 _id 필드에는 고유한 값을 가져야한다.
    • _id 필드의 값으로 ObjectId 외에도 다양한 데이터 유형을 사용할 수 있다. 예를 들어, 문자열, 숫자, 또는 다른 유형의 데이터도 사용할 수 있다.
    • _id 필드는 필수적이지 않지만, 일반적으로 생략되거나 자동으로 생성되지 않는 경우 대부분의 경우 몽고DB가 자동으로 생성된다.

차이점:

  • ObjectId는 몽고DB에서 사용되는 고유한 식별자 유형이며, 일반적으로 _id 필드에 자동으로 할당된다.
  • _id 필드는 문서의 기본 키로 사용되며, 여러 유형의 데이터를 포함할 수 있다.

따라서 _id 필드에는 ObjectId 외에도 사용자가 지정한 고유한 값이나 다른 유형의 데이터를 사용할 수 있지만, ObjectId는 몽고DB에서 가장 일반적으로 사용되는 기본 키 유형이다.
좀 더 이해를 돕기 위해 코드로 이해하면 아래와 같다.

// MongoDB 모듈을 가져옴
const { MongoClient, ObjectId } = require('mongodb');

// MongoDB 연결 문자열, 디폴트 포트 27017
const uri = 'mongodb://localhost:27017';

// MongoDB 클라이언트 생성
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });

// MongoDB에 연결
client.connect(async (err) => {
    if (err) {
        console.error('Error connecting to MongoDB:', err);
        return;
    }

    console.log('Connected to MongoDB');

    try {
        // MongoDB의 특정 컬렉션에 접근
        const collection = client.db('mydb').collection('users');

        // ObjectId를 직접 생성
        const objectId1 = new ObjectId();
        console.log('Generated ObjectId:', objectId1);

        // `_id` 필드에 ObjectId를 할당하여 새 문서를 삽입
        const result1 = await collection.insertOne({
            _id: objectId1,
            name: 'John',
            age: 30
        });

        console.log('Inserted document with ObjectId:', result1.insertedId);

        // `_id` 필드를 생략하면 몽고DB가 자동으로 ObjectId를 생성
        const result2 = await collection.insertOne({
            name: 'Alice',
            age: 25
        });

        console.log('Inserted document with auto-generated ObjectId:', result2.insertedId);
    } catch (error) {
        console.error('Error:', error);
    } finally {
        // MongoDB 클라이언트를 닫음
        client.close();
    }
});



MongoDB에서 데이터처리

시작과 종료

우선 시작을 위해서는 mongoDB서버를 실행해야한다. mongod.exe 파일을 실행해야되는데 그러기 위해서는 일반적으로는 mongodb/bin 폴더에서 mogod --dbpath d:\mongoDB\test 이런식으로 실행한다. 여기서 dbpath는 데이터가 저장될 물리적인 공간을 지정한다. 여기서 더 자세히 들어가보자.

서버와 클라이언트 실행이 두가지 명령어로 나뉜다.

  1. mongod:

    • mongod 명령어는 MongoDB 서버 데몬을 시작하는 데 사용된다. 이 데몬은 클라이언트 요청을 처리하고 데이터를 관리하며 기타 서버 측 작업을 수행한다.
    • mongod를 실행하면 MongoDB 서버 프로세스가 시작되어 클라이언트가 연결할 수 있다.
    • 데이터 디렉토리, 포트 번호, 로그 파일 위치 등과 같은 설정을 지정하기 위해 구성 파일이나 명령행 옵션을 사용해야 한다.
      mongod --help를 통해 필요한 명령어를 찾아볼 수 있다.
    • 일반적으로 mongod 명령어는 백그라운드에서 데몬이나 서비스로 실행된다.
  2. mongo:

    • mongo 명령어는 MongoDB 쉘을 시작하는 데 사용된다. MongoDB 쉘은 MongoDB에 대한 대화형 자바스크립트 인터페이스이다.
    • 이를 통해 사용자는 MongoDB 인스턴스에 연결하고 쿼리를 실행하며 관리 작업을 수행하고 JavaScript와 비슷한 구문을 사용하여 데이터베이스와 상호 작용할 수 있다.
    • mongo 명령어를 인수없이 실행하면 로컬 컴퓨터의 기본 포트(27017)에서 실행 중인 MongoDB 서버에 연결된다.

요약하면 mongo는 데이터베이스와 상호 작용하기 위해 MongoDB 쉘을 시작하는 데 사용되고, mongod는 MongoDB 서버 프로세스 자체를 시작하는 데 사용된다. mongo 쉘은 mongod에 의해 시작된 MongoDB 서버에 연결하여 데이터베이스에 대한 명령과 쿼리를 실행한다.



더 추가적으로 관리하기 위한 설정을 해보자.

  1. vi /etc/mongod.conf: MongoDB의 설정 파일인 mongod.conf에 MongoDB 서버가 수신 대기할 IP 주소를 지정하는 옵션인 bindIp가 있다. 이는 MongoDB 서버가 클라이언트 연결을 수락할 IP 주소를 결정한다. 여기서 bindIp: 0.0.0.0은 MongoDB가 모든 네트워크 인터페이스에서 들어오는 연결을 수락한다는 것을 의미한다.

  2. vi /usr/lib/systemd/system/mongod.service: 이 명령어는 MongoDB 서비스의 unit 파일인 mongod.service를 편집한다. 이 파일에는 MongoDB 서버가 어떻게 시작되는지에 대한 정보가 포함되어 있다. 이파일에서 이렇게 수정해서 ExecStart=/usr/bin/mongod --auth --config /etc/mongod.conf systemd가 몽고DB서비스를 시작할 때 사용한다. ExecStart는 서비스가 시작될 때 실행될 명령을 지정하는 부분이다. /usr/bin/mongod는 mongod 실행 파일의 경로이며, --auth --config /etc/mongod.conf는 실행 시 사용할 옵션이다. --auth는 인증을 활성화하고, --config /etc/mongod.conf는 설정 파일을 /etc/mongod.conf에서 읽도록 지정합니다.

위 파일들을 편집한 후 사용해야할 명령어들은 아래와 같다.

  1. systemctl daemon-reload: 이 명령어는 systemd에게 유닛 파일이 변경되었음을 알려준다. 유닛 파일이 변경되면 systemd가 이를 인식하고 새로운 구성을 적용하기 위해 데몬을 다시로드해야 한다.

  2. systemctl restart mongod: 이 명령어는 MongoDB 서비스를 다시 시작한다. 이렇게 하면 MongoDB가 새로운 구성 옵션을 적용하고 새로운 구성 파일을 사용하여 다시 시작된다.

  3. systemctl status mongod: 이 명령어는 MongoDB 서비스의 현재 상태를 확인한다. MongoDB 서버가 정상적으로 시작되었는지, 실행 중인지 등을 확인할 수 있다.

이러한 과정을 통해 MongoDB의 구성을 변경하고 서버를 다시 시작하여 변경 사항을 적용할 수 있다.


그렇다면 종료하기 위해서는 어떻게 해야될까?
  1. mongod 프로세스 종료:
    터미널에서 mongod 프로세스를 실행한 경우, 해당 터미널에서 Ctrl + C를 눌러서 프로세스를 종료할 수 있다. 이는 일시적으로 mongod를 중지하는 방법이다.

  2. mongod 서비스 종료:
    서버에서 mongod를 서비스로 실행 중이라면, 서버 관리자 권한으로 아래 명령을 사용하여 mongod 서비스를 중지할 수 있다.

    sudo systemctl stop mongod
  3. mongod 프로세스를 직접 종료:
    mongod 프로세스의 PID(Process ID)를 확인한 후 kill 명령어를 사용하여 해당 프로세스를 종료할 수도 있다.

    ps aux | grep mongod
    kill -9 <mongod_pid>
  1. mongod 인스턴스에 접속하여 종료:
    mongo 셸을 사용하여 mongod 인스턴스에 접속한 후 shutdown() 명령어를 사용하여 mongod를 종료할 수도 있다.
    mongo
    > use admin
    > db.shutdownServer()

이때 반드시 admin데이터베이스로 이동해야된다.
만약 다른 데이터베이스에서 저 명령어를 실행하게되면 아래와 같은 에러가 발생한다.



Collection 데이터 관리

MongoDB에서는 컬렉션(Collection)을 사용하여 데이터를 저장한다. 컬렉션은 문서(document)들의 모음이며, 이 문서들은 BSON(Binary JSON) 형식으로 저장된다. 코드와 함께 주요내용들을 파악해보자.

정형화된 데이터 구성요소

MongoDB의 컬렉션은 정형화된 데이터 구성요소가 결정되지 않아도 된다. 즉, 컬럼명, 데이터 타입과 길이, 제약 조건 등을 미리 정의하지 않고도 데이터를 저장할 수 있다.

Collection 생성 관리

  1. Capped Collection (용량 제한 컬렉션)

    • 최초 제안된 크기로 생성된 공간 내에서만 데이터를 저장한다.
    • 최초의 공간이 모두 사용되면 처음으로 돌아가서 기존 공간을 재사용한다.
    • 로그 데이터와 같이 일정한 기간 내에서만 저장, 관리가 필요한 데이터에 적합하다.
    • 생성 방법: db.createCollection("collection_name", { capped: true, size: <size_in_bytes> })
  2. Non-Capped Collection (용량 제한이 없는 컬렉션)

    • 관계형 데이터베이스의 테이블과 유사하게 디스크 공간이 허용하는 범위 내에서 데이터를 저장할 수 있다.
    • 일반적인 데이터 저장에 사용된다.

Collection 생성

// Capped Collection 생성
db.createCollection("capped_collection", { capped: true, size: 100000 })

// Non-Capped Collection 생성
db.createCollection("non_capped_collection")

Collection의 현재 상태 및 정보

// 컬렉션의 상태 및 정보 확인
db.capped_collection.validate()

Collection의 삭제

// 컬렉션 삭제
db.capped_collection.drop()

용량 Collection 비교

db.createCollection("s_emp") 을 통해서 생성했을 때, 즉 용량 제한이 없을 때를 db.s_emp.stats() 을 통해 비교해보자

// 초기값
{
        "ns" : "test.s_emp",
        "size" : 0,
        "count" : 0,
        "storageSize" : 4096,
        "freeStorageSize" : 0,
        "capped" : false,
        "wiredTiger" : {
          ...
        "nindexes" : 1,
        "indexBuilds" : [ ],
        "totalIndexSize" : 4096,
        "totalSize" : 8192,
        "indexSizes" : {
                "_id_" : 4096
        },
        "scaleFactor" : 1,
        "ok" : 1
}

for (var n=1; n<= 20000; n++) db.s_emp.insert({eno:n, m:"test"})
//위코드 실행 후
{
        "ns" : "test.s_emp",
        "size" : 940000,
        "count" : 20000,
        "avgObjSize" : 47,
        "storageSize" : 4096,
        "freeStorageSize" : 0,
        "capped" : false,
        "wiredTiger" : {
         ...
        "nindexes" : 1,
        "indexBuilds" : [ ],
        "totalIndexSize" : 4096,
        "totalSize" : 8192,
        "indexSizes" : {
                "_id_" : 4096
        },
        "scaleFactor" : 1,
        "ok" : 1
}

이렇게 크기가 늘어난 것을 볼 수 있다.
db.createCollection("s_emp",{capped:true, size:8192}) 이 명령어를 통해 크기를 제한해보자.

// 초기값
{
        "ns" : "test.s_emp",
        "size" : 0,
        "count" : 0,
        "storageSize" : 4096,
        "freeStorageSize" : 0,
        "capped" : true,
        "max" : -1,
        "maxSize" : 8192,
        "sleepCount" : 0,
        "sleepMS" : 0,
        "wiredTiger" : {
          ...
        "nindexes" : 1,
        "indexBuilds" : [ ],
        "totalIndexSize" : 4096,
        "totalSize" : 8192,
        "indexSizes" : {
                "_id_" : 4096
        },
        "scaleFactor" : 1,
        "ok" : 1
}

for (var n=1; n<= 20000; n++) db.s_emp.insert({eno:n, m:"test"})
//위코드 실행 후

{
        "ns" : "test.s_emp",
        "size" : 8178,
        "count" : 174,
        "avgObjSize" : 47,
        "storageSize" : 20480,
        "freeStorageSize" : 0,
        "capped" : true,
        "max" : -1,
        "maxSize" : 8192,
        "sleepCount" : 0,
        "sleepMS" : 0,
          ...
        "nindexes" : 1,
        "indexBuilds" : [ ],
        "totalIndexSize" : 20480,
        "totalSize" : 40960,
        "indexSizes" : {
                "_id_" : 20480
        },
        "scaleFactor" : 1,
        "ok" : 1
}

size 값을 보면 크기가 제한돼서 할당된 것을 확인할 수 있다.




다음 포스팅에서는 몽고db의 문법들에 대해서 적어보겠다.

profile
모두가 정보를 습득할 수 있도록 냠냠쩝쩝 먹어보는 공간

0개의 댓글