18. MongoDB Query Part 8. - cursors

이번 포스팅에서는 Cursors에 대해 알아보도록 하겠습니다.

Cursors는 MongoDB가 find() 메써드를 통해 넘겨주는 결과의 집합입니다.

Cursors를 통해 클라이언트-사이드에서는 반복 처리 등 다양한 처리가 가능합니다. DB가 넘겨주는 결과수를 제한할 수 있으며, 결과의 개수를 건너뛸 수 있으며, key 조합을 통해 결과를 분류하거나 검색 방향을 제어할 수 있는 등 기타 강력한 오퍼레이션을 구성할 수 있습니다.

우선 간단한 예로써, 각 도큐먼트에 1에서 100까지의 정수를 저장하는 JavaScript를 작성해 보도록 하겠습니다:

for(i=1; i<101; i++) {
    db.count.insert({cnt : i});
}

var myCursor = db.count.find();

Shell에서 다음과 같이 cursor를 입력하면, 도큐먼트가 20개까지 출력되는 것을 확인할 수 있을 것입니다.

> myCursor
{ "_id" : ObjectId("52f381cc2d911bccacf21963"), "cnt" : 1 }
{ "_id" : ObjectId("52f381cc2d911bccacf21964"), "cnt" : 2 }
{ "_id" : ObjectId("52f381cc2d911bccacf21965"), "cnt" : 3 }
{ "_id" : ObjectId("52f381cc2d911bccacf21966"), "cnt" : 4 }
{ "_id" : ObjectId("52f381cc2d911bccacf21967"), "cnt" : 5 }
{ "_id" : ObjectId("52f381cc2d911bccacf21968"), "cnt" : 6 }
{ "_id" : ObjectId("52f381cc2d911bccacf21969"), "cnt" : 7 }
{ "_id" : ObjectId("52f381cc2d911bccacf2196a"), "cnt" : 8 }
{ "_id" : ObjectId("52f381cc2d911bccacf2196b"), "cnt" : 9 }
{ "_id" : ObjectId("52f381cc2d911bccacf2196c"), "cnt" : 10 }
{ "_id" : ObjectId("52f381cc2d911bccacf2196d"), "cnt" : 11 }
{ "_id" : ObjectId("52f381cc2d911bccacf2196e"), "cnt" : 12 }
{ "_id" : ObjectId("52f381cc2d911bccacf2196f"), "cnt" : 13 }
{ "_id" : ObjectId("52f381cc2d911bccacf21970"), "cnt" : 14 }
{ "_id" : ObjectId("52f381cc2d911bccacf21971"), "cnt" : 15 }
{ "_id" : ObjectId("52f381cc2d911bccacf21972"), "cnt" : 16 }
{ "_id" : ObjectId("52f381cc2d911bccacf21973"), "cnt" : 17 }
{ "_id" : ObjectId("52f381cc2d911bccacf21974"), "cnt" : 18 }
{ "_id" : ObjectId("52f381cc2d911bccacf21975"), "cnt" : 19 }
{ "_id" : ObjectId("52f381cc2d911bccacf21976"), "cnt" : 20 }
Type "it" for more

위의 Shell에 출력된 부분의 가장 아래 라인에서 보는 것처럼 it를 입력하면 계속해서 20개씩 도큐먼트를 출력할 수 있습니다.

만약 it를 입력하여 다음 20개의 도큐먼트를 출력하지 않았다면, 현재 커서의 위치는 20번째 도큐먼트에 있을 것입니다. 만약 커서를 다음 도큐먼트(cnt: 21)로 이동하려면 다음 명령을 수행합니다:

> var myDocument = myCursor.hasNext() ? myCursor.next() : null;
> myDocument
{ "_id" : ObjectId("52f381cc2d911bccacf21977"), "cnt" : 21 }

myCusor.hasNext()는 다음 도큐먼트가 있는지 검사합니다. 있다면 true를, 없다면 false를 반환한다. 만약 myCusor.hasNext()true이라면, 커서는 다음 도큐먼트로 이동(myCursor.next())하고 없으면 null을 변수 myDocument에 저장합니다.

앞서 myCursor가 20번째 도큐먼트에 있었다면 myDocument는 21번째 도큐먼트를 가리키고 있을 것입니다.

각각의 도큐먼트에 대해 무엇인가를 처리하고자 한다면 다음과 같이 while문을 사용합니다:

while (myCursor.hasNext()) {
    obj = myCursor.next();
    // do something you want
}

만약 처음 10개의 도큐먼트를 건너뛴 후 다음 5개의 도큐먼트를 출력하려면 다음과 같이 입력합니다:

> var myCursor = db.count.find().sort({cnt : 1}).limit(5).skip(10);
> myCursor
{ "_id" : ObjectId("52f381cc2d911bccacf2196d"), "cnt" : 11 }
{ "_id" : ObjectId("52f381cc2d911bccacf2196e"), "cnt" : 12 }
{ "_id" : ObjectId("52f381cc2d911bccacf2196f"), "cnt" : 13 }
{ "_id" : ObjectId("52f381cc2d911bccacf21970"), "cnt" : 14 }
{ "_id" : ObjectId("52f381cc2d911bccacf21971"), "cnt" : 15 }

skip(x)x개 만큼을 건너뛰고, limit(y)y개 만큼을 출력하라는 의미입니다.

위의 명령어는 다음 명령어와도 동일합니다:

var myCursor = db.count.find().limit(5).sort({cnt : 1}).skip(10);
var myCursor = db.count.find().skip(10).limit(5).sort({cnt : 1});