본문 바로가기

Programming/Database & Docker

[MongoDB] 기존 Document에 새로운 필드 추가하기 (확장)

처음 구성한 스키마대로 서비스가 운영되면 정말 좋겠지만, 서비스의 확장과 같은 이유로 스키마를 수정해나가야하는 경우가 생긴다.

 

글만 작성할 수 있었던 서비스에 댓글과 조회수 기능을 추가하려고 한다. 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이다.

현재 collection의 구조

그렇다면, 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

 

Mongoose v5.9.6: Schemas

Schemas If you haven't yet done so, please take a minute to read the quickstart to get an idea of how Mongoose works. If you are migrating from 4.x to 5.x please take a moment to read the migration guide. Everything in Mongoose starts with a Schema. Each s

mongoosejs.com

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에서는 어떻게 스키마를 확장하는지 작성해보려고 한다.

반응형