내가 아직 다뤄본 적이 없는 nosql 데이터베이스 시스템에 대해서 정리해보고자 이 글을 작성한다. (사진은 테이블이 없는 몽고db의 특징 ㅋㅋ)
위처럼 sql과 몽고db의 사용용어가 다르다.
컬렉션의 경우 문서들의 집합이며 각 문서는 필드와 값의 쌍으로 구성된다. 이때 필드는 특정 값이나 데이터 유형을 포함한다. 그리고 mongodb에서 기본 키 역할을 하는 것은 ObjectID
이며 mongodb에서 자동으로 생성되는 고유한 식별자이다.
여기서 기본키에 대해서 좀 더 자세히 설명하자면 아래와 같다.
ObjectId:
ObjectId
는 몽고DB에서 기본적으로 사용되는 고유한 식별자이다.ObjectId
는 BSON(Object Notation) 데이터 형식에서 사용되며, 다양한 클라이언트 라이브러리와 몽고DB 셸에서 자동으로 생성된다._id
필드에 ObjectId
를 할당한다.66024d63abe17c97531a9d35
이런식으로 발급되는데 이는 이렇게 슬라이싱 된다.66024d63 / abe17c / 9753 / 1a9d35
_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서버를 실행해야한다. mongod.exe
파일을 실행해야되는데 그러기 위해서는 일반적으로는 mongodb/bin
폴더에서 mogod --dbpath d:\mongoDB\test
이런식으로 실행한다. 여기서 dbpath
는 데이터가 저장될 물리적인 공간을 지정한다. 여기서 더 자세히 들어가보자.
서버와 클라이언트 실행이 두가지 명령어로 나뉜다.
mongod:
mongod
명령어는 MongoDB 서버 데몬을 시작하는 데 사용된다. 이 데몬은 클라이언트 요청을 처리하고 데이터를 관리하며 기타 서버 측 작업을 수행한다.mongod
를 실행하면 MongoDB 서버 프로세스가 시작되어 클라이언트가 연결할 수 있다.mongod --help
를 통해 필요한 명령어를 찾아볼 수 있다.mongod
명령어는 백그라운드에서 데몬이나 서비스로 실행된다.mongo:
mongo
명령어는 MongoDB 쉘을 시작하는 데 사용된다. MongoDB 쉘은 MongoDB에 대한 대화형 자바스크립트 인터페이스이다.mongo
명령어를 인수없이 실행하면 로컬 컴퓨터의 기본 포트(27017)에서 실행 중인 MongoDB 서버에 연결된다.요약하면
mongo
는 데이터베이스와 상호 작용하기 위해 MongoDB 쉘을 시작하는 데 사용되고,mongod
는 MongoDB 서버 프로세스 자체를 시작하는 데 사용된다.mongo
쉘은mongod
에 의해 시작된 MongoDB 서버에 연결하여 데이터베이스에 대한 명령과 쿼리를 실행한다.
더 추가적으로 관리하기 위한 설정을 해보자.
vi /etc/mongod.conf
: MongoDB의 설정 파일인 mongod.conf
에 MongoDB 서버가 수신 대기할 IP 주소를 지정하는 옵션인 bindIp
가 있다. 이는 MongoDB 서버가 클라이언트 연결을 수락할 IP 주소를 결정한다. 여기서 bindIp: 0.0.0.0
은 MongoDB가 모든 네트워크 인터페이스에서 들어오는 연결을 수락한다는 것을 의미한다.
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
에서 읽도록 지정합니다.
위 파일들을 편집한 후 사용해야할 명령어들은 아래와 같다.
systemctl daemon-reload
: 이 명령어는 systemd에게 유닛 파일이 변경되었음을 알려준다. 유닛 파일이 변경되면 systemd가 이를 인식하고 새로운 구성을 적용하기 위해 데몬을 다시로드해야 한다.
systemctl restart mongod
: 이 명령어는 MongoDB 서비스를 다시 시작한다. 이렇게 하면 MongoDB가 새로운 구성 옵션을 적용하고 새로운 구성 파일을 사용하여 다시 시작된다.
systemctl status mongod
: 이 명령어는 MongoDB 서비스의 현재 상태를 확인한다. MongoDB 서버가 정상적으로 시작되었는지, 실행 중인지 등을 확인할 수 있다.
이러한 과정을 통해 MongoDB의 구성을 변경하고 서버를 다시 시작하여 변경 사항을 적용할 수 있다.
mongod 프로세스 종료:
터미널에서 mongod
프로세스를 실행한 경우, 해당 터미널에서 Ctrl + C
를 눌러서 프로세스를 종료할 수 있다. 이는 일시적으로 mongod를 중지하는 방법이다.
mongod 서비스 종료:
서버에서 mongod
를 서비스로 실행 중이라면, 서버 관리자 권한으로 아래 명령을 사용하여 mongod 서비스를 중지할 수 있다.
sudo systemctl stop mongod
mongod 프로세스를 직접 종료:
mongod 프로세스의 PID(Process ID)를 확인한 후 kill
명령어를 사용하여 해당 프로세스를 종료할 수도 있다.
ps aux | grep mongod
kill -9 <mongod_pid>
mongo
셸을 사용하여 mongod 인스턴스에 접속한 후 shutdown()
명령어를 사용하여 mongod를 종료할 수도 있다.mongo
> use admin
> db.shutdownServer()
이때 반드시 admin데이터베이스로 이동해야된다.
만약 다른 데이터베이스에서 저 명령어를 실행하게되면 아래와 같은 에러가 발생한다.
MongoDB에서는 컬렉션(Collection)을 사용하여 데이터를 저장한다. 컬렉션은 문서(document)들의 모음이며, 이 문서들은 BSON(Binary JSON) 형식으로 저장된다. 코드와 함께 주요내용들을 파악해보자.
MongoDB의 컬렉션은 정형화된 데이터 구성요소가 결정되지 않아도 된다. 즉, 컬럼명, 데이터 타입과 길이, 제약 조건 등을 미리 정의하지 않고도 데이터를 저장할 수 있다.
Capped Collection (용량 제한 컬렉션)
db.createCollection("collection_name", { capped: true, size: <size_in_bytes> })
Non-Capped Collection (용량 제한이 없는 컬렉션)
// Capped Collection 생성
db.createCollection("capped_collection", { capped: true, size: 100000 })
// Non-Capped Collection 생성
db.createCollection("non_capped_collection")
// 컬렉션의 상태 및 정보 확인
db.capped_collection.validate()
// 컬렉션 삭제
db.capped_collection.drop()
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의 문법들에 대해서 적어보겠다.