처음 구성한 스키마대로 서비스가 운영되면 정말 좋겠지만, 서비스의 확장과 같은 이유로 스키마를 수정해나가야하는 경우가 생긴다.
글만 작성할 수 있었던 서비스에 댓글과 조회수 기능을 추가하려고 한다. MongoDB는 NoSQL으로 언제든지 스키마의 확장이 가능하다. 이 글에서는 스키마를 어떻게 확장하는지에 대해 작성해보았다.
1. 현재 DB는 어떤 상태인가?
Mongo Shell을 실행시켜보자.
$ mongo
현재 나의 db list와 collection list를 확인해보자. 현재 내 DB의 이름은 post이며 collections의 이름은 posts이다.
> show dbs
post 0.000GB
> use post
switched to db post
> show collections
posts
현재 document는 다음과 같이 구성되어있다.
여기서 _id, title, author ...은 key이고 오른쪽에 있는 값들은 key의 type이다.
그렇다면, posts collection의 document list를 확인해보자. pretty()를 붙여주면 예쁘게 값을 보여준다.
# db.COLLECTION_NAME.find()
> db.posts.find().pretty()
{
"_id" : ObjectId("5e7cb758875957a5eb18985f"),
"title" : "Hi MongoDB",
"author" : "seohyun",
"content" : "Welcome!",
"createdAt" : ISODate("2020-03-26T14:08:24.744Z"),
"updatedAt" : ISODate("2020-03-26T14:08:24.744Z"),
"__v" : 0
}
참고로, mongoose (Object Relational Mapper 라이브러리) 를 사용하고 있는데, __v는 versionKey를 뜯하며, mongoose에 의해 생성된 값이며 default 값은 0이다. versioning 관련해서는 다음에 글을 작성해보도록 하겠다. versioning Docs
2. 어떻게 추가할 것인가? Mongo Shell을 이용해보자
변경하고자하는 Document 구조는 다음과 같다. viewNum과 comments가 추가되었다. 하나의 글에는 여러 개의 댓글이 달릴 수 있으므로, One-to-Many Relationship이다. 이때, Embedded Document pattern을 사용할 수 있다. 새로운 collection의 구조는 아래와 같다.
이미 존재하는 레코드는 viewNum과 comments field가 없는데 어떻게 해야할까? mongo Shell에 아래 명령어를 입력해보자.
2-1. viewNum field 추가하기
먼저, viewNum부터 추가해보자.
# db.COLLECTION_NAME.updateMany({<filter>}, {<update>})
> db.posts.updateMany({}, { $set: { "viewNum": NumberInt(0) } })
1. updateMany
만약 정말 많은 양의 레코드가 존재한다면, 하나씩 업데이트를 하기엔 너무나도 많은 시간이 걸린다. updateMany를 활용하여 여러 개의 레코드를 바꿔보자
2. <filter>
filter option을 통해서 특정 레코드만 업데이트할 수 있다.
# 모든 레코드 변경
{}
# filter를 통해 특정 레코드만 변경
{ "author" : "seohyun" }
3. NumberInt(0)와 0의 차이
그냥 0을 넣게 될 경우, data type이 Double로 설정된다. viewNum은 int형이 알맞으므로, NumberInt를 통해 Int형으로 바꿔주자.
# double형
> db.posts.updateMany({}, { $set: { "viewNum": 0 } })
# int형
> db.posts.updateMany({}, { $set: { "viewNum": NumberInt(0) } })
4. 결과값 보기
위의 명령어를 실행하면, 아래와 같은 결과를 보여준다.
/* 1 */
{
"acknowledged" : true,
"matchedCount" : 10.0,
"modifiedCount" : 10.0
}
acknowledged: wrtie operation이 성공적으로 수행되었는지 알려주는 값
matchedCount: 쿼리문에 해당하는 레코드 수
modifiedCount: 수정된 레코드 수
5. 수정되었는지 확인해보기
# db.COLLECTION_NAME.find()
> db.posts.find().pretty()
...
{
"_id" : ObjectId("5e7cb758875957a5eb18985f"),
"title" : "Hi MongoDB",
"author" : "seohyun",
"content" : "Welcome!",
"createdAt" : ISODate("2020-03-26T14:08:24.744Z"),
"updatedAt" : ISODate("2020-03-26T14:08:24.744Z"),
"__v" : 0,
"viewNum" : 0
}
viewNum값이 0으로 들어간 것을 확인할 수 있다.
2-2. comment field 추가하기
하나의 post에는 여러개의 comment가 존재할 수 있기 때문에 array형을 사용해야한다.
# db.COLLECTION_NAME.updateMany({<filter>}, {<update>})
db.posts.updateMany({}, { $set: { "comments": [{ "comment_id": new ObjectId(), "comment_author": "seohyun", "comment_text": "hello", "comment_createdAt": new Date() }] } })
# 가독성을 위한 indentation
db.posts.updateMany(
{},
{ $set:
{ "comments":
[{
"comment_id": new ObjectId(),
"comment_author": "seohyun",
"comment_text": "hello",
"comment_createdAt": new Date()
}]
}
}
)
comment_id: new ObjectId()를 통해 자동으로 mongodb가 id를 생성해준다.
comment_createdAt: new Date()를 통해 자동으로 현재 시간을 넣어준다.
수정되었는지 확인해보자.
# db.COLLECTION_NAME.find()
> db.posts.find().pretty()
...
{
"_id" : ObjectId("5e7cb758875957a5eb18985f"),
"title" : "Hi MongoDB",
"author" : "seohyun",
"content" : "Welcome!",
"createdAt" : ISODate("2020-03-26T14:08:24.744Z"),
"updatedAt" : ISODate("2020-03-26T14:08:24.744Z"),
"__v" : 0,
"viewNum" : 0,
"comments" : [
{
"comment_id" : ObjectId("5e7d6411fdb642d18789d55f"),
"comment_author" : "seohyun",
"comment_text" : "hello",
"comment_createdAt" : ISODate("2020-03-27T11:25:21.116+09:00")
}
]
}
의도한대로 만들어진 것을 확인할 수 있다.
다음 글에서는 mongo shell이 아닌 mongoose에서는 어떻게 스키마를 확장하는지 작성해보려고 한다.
'Programming > Database & Docker' 카테고리의 다른 글
MongoDB Replica Set 구성하기 - Docker Swarm (1) | 2023.06.04 |
---|---|
Angular + Nginx 도커라이징 (0) | 2020.04.28 |
Node.js 웹 앱의 도커라이징 (0) | 2020.04.28 |
[MongoDB] Mac OS X에서 MongoDB 시작하기 (0) | 2020.03.16 |