몽고디비 autoIncrement가 이해가 안됩니다

조회수 3978회

몽고DB에 AutoIncrement 기능이 없다길래 찾아보니 레퍼런스 문서에서 Collection을 하나 더 만들어서 함수로 구현하는 방법을 제안하더군요

https://docs.mongodb.com/manual/tutorial/create-an-auto-incrementing-field/#auto-increment-optimistic-loop

그래서 한번 코드를 살펴보고 있는데 잘 이해가 안되서 질문올려봅니다.

function insertDocument(doc, targetCollection) {

    while (1) {

        var cursor = targetCollection.find( {}, { _id: 1 } ).sort( { _id: -1 } ).limit(1);

        var seq = cursor.hasNext() ? cursor.next()._id + 1 : 1;

        doc._id = seq;

        var results = targetCollection.insert(doc);

        if( results.hasWriteError() ) {
            if( results.writeError.code == 11000 /* dup key */ )
                continue;
            else
                print( "unexpected error inserting data: " + tojson( results ) );
        }

        break;
    }
}

cursor가 제일 마지막에 있는 document를 찾는다는건 알겠는데 그렇다면 hasNext를 쓰는 이유를 모르겠습니다. 그냥 +1해서 _id로 사용하면 AI가 되는거 아닌가요? 그리고 Counter용 Collection이 필요한 이유도 모르겠고요.

한가지 더 질문드리자면 document 중에서 일부가 삭제되었을때 삭제된 id값부터 채워넣는 방식으로 구현하는 방법은 없을까요? 처음부터 탐색해나가거나 삭제될때 인덱싱을 하도록 하는 방법을 생각해보고는 있는데 다른 방법이 있는지 궁금합니다.

1 답변

  • 좋아요

    0

    싫어요
    채택 취소하기

    첫번째 질문에 대한 답변

    우선 위의 코드에 대한 설명을 하면, Cursor는 일종의 Iterator 입니다.

    문제는 해당 컬렉션에 (가)값이 전혀 없는 경우와 (나)하나의 이상의 값이 있는 경우로 나눠볼 수 있습니다.

    일단 (나) 의 경우는 cursor에 절대적으로 컬렉션의 마지막 값 한개가 무조건 들어있습니다. 따라서 iterator인 cursor에서 next() 연산을 통해서 가져올 수 있습니다.

    그러나 (가) 의 경우에는 값이 없으므로, next() 연산을 에러를 발생 시킵니다.

    iterator에서 next()할 수 있는 값이 있는지 없는 지 알 수 있는 방법이 hasNext() 가 되겠죠?

    따라서, 위의

    var seq = cursor.hasNext() ? cursor.next()._id + 1 : 1;
    

    구문은 마지막 id 값을 얻는 경우(hasNext가 true)인 경우와 최초에 컬렉션에 등록하는 경우(hasNext가 false) 인 경우로 나눠서 최초인 경우는 id를 1로 만듭니다.

    보통의 트랜잭션을 지원하는 DB의 경우는 트랜잭션 안에서 한 컬럼의 값을 증가하는 방식을 사용합니다. (똑같은 ID가 사용될 가능성을 배제하기 위해서).

    Seq NextKey
    User 1

    새로운 User가 등록되면 트랜잭션 안에서 Seq가 User인 NextKey를 읽어와 사용하고, 이에 1 증가한 값을 다시 저장하는 방식을 사용합니다.

    Seq NextKey
    User 2

    .

    두번째 질문에 대한 답변

    삭제된 id 값을 찾으려면, 전체 문서를 다 찾아봐야되는데, 그렇게 되면 Insertion 비용에 검색 비용이 들어갑니다. 전체적으로 유지되는 데이터셋(컬렉션)의 크기가 일정한 규모로 유지되는 것이 확실하다면 시도해봄직 합니다만, 점점 커질 가능성이 높은 경우라면, 검색 비용이 계속 증가하게 될텐데, 이는 곧 새로운 데이터를 추가하는 비용(시간)도 점점 커지게됨으로 상당히 비효율적이게 됩니다.

    차선으로 삭제될 때, 삭제된 id 풀을 만들어 재활용을 고민해볼 수도 있겠습니다.

    다만 삭제된 id를 재활용해야 할 정도로 데이터가 매우 많이 발생하는 것인지 혹은 데이터가 빈번히 삭제되는 시스템이어서 id의 소모가 빠른 경우인지 등, id가 증가하여 앞으로 사용할 수 있는(가용) id의 부족 상황이 도래하는지 고민할 필요가 있어보입니다.

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)