본문 바로가기

오픈소스/mongodb

몽고디비 궁금한 점들

  • 타임존이 다를때 ISODate 일자 별 집계 문제점
    • 한국은 GMT+9 이므로, "$dayOfMonth" 함수를 통해 집계하면 9시간 당겨 출력
    • "$dateToString" 함수와 "$add" 함수를 통해 9시간을 더해 준 뒤에 집계
    • 실제 자바 프로그램 상에서 Date 함수를 사용하면 되기 때문에 문제는 없음
    • 단, 외부 입력일자가 없는 집계인 경우 Group By Month 는 문제가 됨
d1 = ISODate("2015-06-12T23:00:00.000Z")
d2 = ISODate("2015-06-13T00:00:00.000Z")
d3 = ISODate("2015-06-13T01:00:00.000Z")
d4 = ISODate("2015-06-13T02:00:00.000Z")
d5 = ISODate("2015-06-13T03:00:00.000Z")
d6 = new Date() // "date" : ISODate("2015-06-13T04:18:31.201Z") - 현재시간 6/13 오후 13:19분

db.test.drop()
db.test.insert({date: d1})
db.test.insert({date: d2})
db.test.insert({date: d3})
db.test.insert({date: d4})
db.test.insert({date: d5})
db.test.insert({date: d6})

db.test.aggregate([
{$project:{
    "dt": { $dateToString: { format: "%Y-%m-%d", date: {$add:["$date", 3600*9*1000]} } },
    // 이와 같이 9시간을 더해 주어야 정상적인 시간 계산이 가능하다.   
    "year": { $year: { $add: [ "$date", 3600 * 9 * 1000 ] } },
    "month":{$month:{$add:["$date", 3600*9*1000]}},
    "day1":{$dayOfMonth:{$add:["$date", 3600*9*1000]}},
    "day2":{$dayOfMonth:{$subtract:["$date", 0]}},
    "day3":{$substr:["$date", 0, 10]},
    "day4":"$date"
}},
{$group: {_id:"$dt", count:{$sum:1}}},
{$sort: {_id:1}}
])

"_id" : "2015-06-13",
"count" : 6.0000000000000000
  • 단순 for ... loop 통한 문서 생성
for(i=0; i < 10; ++i) {
  db.posts.insert({
    title: "A MongoDB Article"
  });
}

  • 결과 커서를 혹은 데이터베이스, 컬렉션을 for ... each 통해서 탐색할 수 없나?
var myCursor = db.test.find();

while (myCursor.hasNext()) {
   print(tojson(myCursor.next()));
}
  • ISODate 직접입력 및 GMT 출력방법
isoDate = ISODate("2015-06-12T23:00:00.000Z")
isoDate.toTimeString()

ISODate("2015-06-12T23:00:00Z")
08:00:00 GMT+0900 (KST)
  • 터미널에서 직접 스크립트 실행하는 방법

var start = new Date();

db.foo.find({dt:{$gte:"20150201", $lt:"20150301"}}, {_id:0, dt:1});

var end = new Date();

print('> Took ' + (end - start) + ' ms');

psyoblade@ mongodb] > bin/mongo localhost/test asdf.js

  • 몽고 콘솔에서 직접 스크립트 실행하는 방법

> load("./asdf.js")

  • 몽고 콘솔에서 편집기(vi)를 사용하는 방법
psyoblade@ mongodb] > export EDITOR=vim

MongoDB shell version: 2.2.0
> function f() {}
> edit f
> f
function f() {
    print("this really works");
}
> f()
this really works
> o = {}
{ }
> edit o
> o
{ "soDoes" : "this" }
>
  • set 은 object 로 표현되는 것 같은데 문서 내의 set 필드에 하나씩 추가할 수 없나?
    • $set 함수가 항상 전체를 get & set 하는 방법 밖에 없는 것 같은데 맞나?
    • set 안에 set 을 보관하는 경우에도 전체를 set 안하고 일부만 할 수 있나? YES

updating-nested-document-in-mongodb

collection.update({'_id': myid}, {$set: {'anotherdoc.something': 'somenewval'});

  • set vs. array 어떤 경우에 사용하는가?
    • set : 조회 시에 정확한 key 값을 알고 조회할 때
    • array : 조회 시에 임의의 값을 iterating 하거나 aggregate 할 필요가 있을 때
db.dummy.drop()
db.dummy.insert({ id:1, nm:"james",
xx:[
{dt:20150101, install:100, purchase:20, session:130},
{dt:20150102, install:10, purchase:10, session:230},
{dt:20150103, install:200, purchase:50, session:330},
{dt:20150104, install:10, purchase:30, session:340},
{dt:20150105, install:1, purchase:40, session:3330}
]})
db.dummy.insert({id:2,nm:"james",
xx:[
{dt:20150101, install:100, purchase:20, session:130},
{dt:20150102, install:10, purchase:10, session:230},
{dt:20150103, install:200, purchase:50, session:330},
{dt:20150104, install:10, purchase:30, session:340},
{dt:20150105, install:1, purchase:40, session:3330}
]})
> db.dummy.aggregate([{$match:{id:{$gte:2}}}, {$project: {xx:1}}, {$unwind:'$xx'}])

{ "_id" : 20150101, "install" : 200, "purchase" : 200, "session" : 200 }

{ "_id" : 20150102, "install" : 20, "purchase" : 20, "session" : 20 }

{ "_id" : 20150103, "install" : 400, "purchase" : 400, "session" : 400 }

{ "_id" : 20150104, "install" : 20, "purchase" : 20, "session" : 20 }

{ "_id" : 20150105, "install" : 2, "purchase" : 2, "session" : 2 }

   
* array 형태로 저장하면,, unwind nested document 형태로 aggregate 해서 출력이 가능함.


"Tailor your schema to your application workload"

결론은 어플리케이션에 맞게 스키마를 잘 설계 하라

  1. 문서 단위와 이벤트 단위는 항상 같지 않다
    1. 메모리 기반 몽고디비의 경우 malloc 대신 memset 이 낫기 때문에 insert 된 문서에 업데이트 하는 것이 효과적이다.
    2. 문서가 많아 질 수록 _id 또한 늘어나므로 문서 수 자체를 줄이는 것이 유용하며, 약 10억 _id 값이 32GB 메모리를 차지한다
    3. 하나의 문서에 하나의 이벤트 대신 Set 을 통한 N개의 데이터를 저장하라
      1. Worst : document = event
      2. Better : document = 3600 seconds events
      3. Best : document = { 60 mins * 60 seconds events }


레퍼런스