클라이언트에서 리스트를 보여줄 때, 각 원소들을 정렬해서 보여주는 것에서 나아가 원소들의 순서를 조정해야 하는 경우가 있다. 이때, 사용자가 순서를 명시적으로 지정하게 하는 것보다 드래그-앤-드롭 기능을 사용하여 수정하게 하면 더 긍정적인 사용자 경험을 창출할 수 있다.
하지만 드래그-앤-드롭 기능은, 프론트엔드는 물론이고 백엔드에게도 꽤나 챌린징한 태스크다. 특히 원소 간 순서 조정이라는 문제를 보이는 그대로 접근했다가는 비효율적인 쿼리를 만들게 될 수 있다. 이를 알아보자.
노션 역시 각 데이터를 '블록' 단위로 관리하고 있다. 하나의 문서는 이 블록들의 조합으로 만들어진다. 이 블록들은 UUID 값으로 식별된다. 실제로 '블록 링크 복사' 후 해당 링크의 URL을 보면
- PK-인덱스 불일치
- 다른 블록들 사이로 드래그-앤-드롭한다면?
대충 리턴하는 JSON Array의 인덱스로 해결 가능
요구사항에 따르면 도큐먼트 블록 간에는 순서 조정이 빈번히 발생한다. 그리고 드물게 블록 추가가 발생할 수 있다.
만약 블록 자체의 순서를 바꾸려면 어떻게 해야할까? 다양한 구현 방법이 있겠지만, 블록 테이블에 '인덱스' 칼럼을 추가하는 것을 고려해볼 수 있다. 인덱스는 클라이언트의 편의성을 위해 1부터 시작한다.
블록 ID | 블록 내용 | 인덱스 |
---|---|---|
1 | content 1 | 1 |
2 | content 2 | 2 |
3 | content 3 | 3 |
가장 이상적인 블록 테이블은 이런 느낌일 것이다. 실제로는 각 블록이 속한 도큐먼트를 지정하기 위하여 도큐먼트 ID를 FK로 가지겠지만 여기서는 하나의 도큐먼트만 존재한다고 가정하고, 다른 칼럼은 생략하도록 하겠다.
먼저 인덱스 칼럼이 존재하는 경우 PK와 인덱스가 분리되므로 불일치 문제를 해결할 수 있다.
만약 마지막 레코드를 삭제하고 새로운 레코드를 4개 추가한다고 할 때, 우리가 원하는 인스턴스는 다음과 같을 것이다.
블록 ID | 블록 내용 | 인덱스 |
---|---|---|
1 | content 1 | 1 |
2 | content 2 | 2 |
4 | content 4 | 3 |
5 | content 5 | 4 |
6 | content 6 | 5 |
7 | content 7 | 6 |
첫번째로 추가된 레코드와 삭제된 레코드의 ID는 다르지만, 같은 위치에 존재해야 하므로 인덱스는 같아야 한다.
만약 6번 (인덱스에 해당하는) 블록을 1번 블록과 2번 블록 사이에 드래그-앤-드롭하고 싶다고 하자.
블록 ID | 블록 내용 | 인덱스 |
---|---|---|
1 | content 1 | 1 |
7 | content 7 | 2 |
2 | content 2 | 3 |
4 | content 4 | 4 |
5 | content 5 | 5 |
6 | content 6 | 6 |
문제는 중간 삽입으로 인해 2번 인덱스 아래로 줄줄이 update 쿼리를 발생시키게 되었다는 것이다. 비슷한 문제를 어디서 보지 않았는가? 맞다. ArrayList의 삽입