막연히 NoSQL이 좋다고 생각해서 MongoDB를 쓰다가 설계에 막혀 답답했던 적이 있다. 그래서 찾아보다가 발견한 mongodb 블로그에 있는 글을 토대로 MongoDB 설계 시 무엇을 고려해야 하는지 정리해보았다.
RDBMS에서는 1:N으로 쓰면 되는 관계를 MongoDB에서는 N의 수가 얼마나 되느냐에 따라 설계를 다르게 해야 한다고 한다.
아주 적은 수의 Many에 대한 경우다. 이 경우 MongoDB에선 Embeded Document를 활용할 수 있다.
> db.person.findOne()
{
name: 'Kate Monster',
ssn: '123-456-7890',
addresses : [
{ street: '123 Sesame St', city: 'Anytown', cc: 'USA' },
{ street: '123 Avenue Q', city: 'New York', cc: 'USA' }
]
}
장점.
단점.
많은 수의 N에 대한 경우다. 제품과 부품의 관계를 예로 들어 설명이 되어있다.
한 제품에는 수백개의 부품이 존재할 수 있다. 이 경우 부모가 되는 Document에 ObjectID를 저장하여 referencing을 할 수 있다.
부품.
> db.parts.findOne()
{
_id : ObjectID('AAAA'),
partno : '123-aff-456',
name : '#4 grommet',
qty: 94,
cost: 0.94,
price: 3.99
제품.
> db.products.findOne()
{
name : 'left-handed smoke shifter',
manufacturer : 'Acme Corp',
catalog_number: 1234,
parts : [ // array of references to Part documents
ObjectID('AAAA'), // reference to the #4 grommet above
ObjectID('F17C'), // reference to a different Part
ObjectID('D2AA'),
// etc
]
장점.
단점.
아주 많은 수의 Many에 대한 경우이다. MongoDB의 Document의 size는 16MB로 제한되어 있다. 12B를 사용하는 ObjectID가 아주 많아지게 되면 문제가 생긴다.
다음 예제는 로그메시지에 대한 것이다. 부모 Document에 자식의 ObjectID를 Array로 저장하는 것이 아닌 자식 Document에 부모의 ObjectID를 저장하는 방식으로 referencing을 할 수 있다.
호스트.
> db.hosts.findOne()
{
_id : ObjectID('AAAB'),
name : 'goofy.example.com',
ipaddr : '127.66.66.66'
}
로그.
>db.logmsg.findOne()
{
time : ISODate("2014-03-28T09:42:41.382Z"),
message : 'cpu is on fire!',
host: ObjectID('AAAB') // Reference to the Host document
}
장점.
단점.
이슈트래킹이나 프로젝트 관리 시스템 같은 경우에 사용할 수 있는 방법이다. 작업을 사람에게 할당할 수 있다. 사람을 조회할 때 작업리스트를 볼 수 있어야 하고, 작업을 조회할 때 어떤 사람에게 할당되었는지 조회 및 수정을 할 수 있어야 한다.
이런 경우 자식 Document에 부모의 ObjectID를 저장하여 양방향 Referencing을 할 수 있다.
사람.
db.person.findOne()
{
_id: ObjectID("AAF1"),
name: "Kate Monster",
tasks [ // array of references to Task documents
ObjectID("ADF9"),
ObjectID("AE02"),
ObjectID("AE73")
// etc
]
}
작업.
db.tasks.findOne()
{
_id: ObjectID("ADF9"),
description: "Write lesson plan",
due_date: ISODate("2014-04-01"),
owner: ObjectID("AAF1") // Reference to Person document
}
장점.
단점.
참조한 블로그의 글은 2014년도에 작성된 글이다. 조인의 경우 어플리케이션 레벨에서 추가적인 쿼리를 실행해야 한다고 나와 있는데, populate 기능이 없던 시절에 작성된 글이 아닌가 싶다.
참조.
https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design