21. MongoDB Query Part 11. - $snap

이전 포스팅에서 약속하였듯이 이번 글에서는 $snapshot 쿼리 옵션에 대해서 자세히 알아보도록 하겠습니다.

일반적인 데이터 처리 절차는 다음과 같습니다:

MongoDB로부터 도큐먼트를 불러오고, 이에 대한 처리를 한 후, 처리에 대한 결과를 다시 저장합니다.

예를 들어 다음 코드를 살펴보도록 하겠습니다.

cursor = db.myCollection.find();
while (cursor.hasNext())
{
  var doc = cursor.next();
  doc = process(doc);
  db.myCollection.save(doc);
}

위의 코드 내용을 살펴보면,

  • 변수 cursormyCollection으로부터 검색된 도큐먼트를 저장하였으며,
  • cursor에 저장된 내용을 변수 doc으로 얻은 후,
  • doc에 대한 처리를 한 후, 처리 결과를 다시 변수 doc으로 저장하고,
  • docmyCollection에 저장(save)하였습니다.
  • 그리고 cursor는 다음 도큐먼트로 이동하여 더이상 도큐먼트가 없을 때까지 이를 반복합니다.

만약 처리된 도큐먼트의 사이즈가 처리되기 전보다 크면 어떤 일이 벌어질까요? 그림을 통해 이에 대한 설명을 하도록 하겠습니다.

이해를 돕기 위해 다음 그림을 살펴보도록 하겠습니다.

[그림 1] 쿼리되는 컬렉션

[그림 1]에서 각 도형을 각각 도큐먼트로 생각하겠습니다. find 명령이 실행될 때 결과는 컬렉션의 시작(가장 왼쪽 도큐먼트)부터 가져오게 되며 하나씩 처리할 때 cursor는 오른쪽으로 이동하게 됩니다.

만약 [그림 2]와 같이 두번째 도큐먼트(녹색 둥근사각형)를 처리한 결과 원래의 사이즈보다 커지면,

[그림 2] 처리된 도큐먼트의 사이즈 변화

처리된 후의 두번째 도큐먼트는 원래의 위치였던 첫번째와 세번째 도큐먼트 사이에 저장 가능한 충분한 크기가 확보되지 않았으므로 새로운 위치로 이동하여야 합니다.

일반적으로 가장 마지막(맨 오른쪽)으로 위치를 옮깁니다.

[그림 3] 처리된 도큐먼트의 위치 이동

이 후, cursor는 다음 도큐먼트로 이동하여 처리를 계속 진행하게 되는데, 이와 같은 식으로 진행하게 되면 [그림 4]와 같이 이미 처리된 도큐먼트를 마지막에 다시 만나게 됩니다.

[그림 4] 처리된 도큐먼트의 위치 이동 후 cursor 배치

이를 해결하고자 하는 것이 바로 snapshot 쿼리 옵션입니다.

$snapshot 쿼리 옵션이 추가되면 쿼리는 도큐먼트 배치를 도큐먼트의 원래 위치로 인식하고 처리하게 됩니다.

쿼리 용법은 다음과 같이 세가지 중 하나를 선택하여 사용할 수 있습니다:

db.myCollection.find().snapshot()
db.myCollection.find()._addSpecial( "$snapshot", true )
db.myCollection.find( { $query: {}, $snapshot: true } )
  • 주의사항
    • sharded collection과 $snapshot을 함께 사용해서는 안 됩니다.
    • $hint 혹은 $orderby와 함께 사용해서도 안 됩니다.