드래그앤드롭으로 객체의 순서가 바뀌는 것을 DB에 어떻게 적용할 수 있을까?

hongo·2023년 7월 22일
3

현재 프로젝트에서 드래그앤드롭으로 아이템의 순서를 변경할 수 있는 기능이 필요한데, 어떻게 구현하면 좋을지 여러 방법들을 찾아보았다.

1. 순서가 바뀐 객체를 포함해, 뒤에 있는 모든 객체들의 순서를 업데이트 한다.

UPDATE item SET order = order +1 WHERE order >= {순서가바뀐객체의 order}

가장 직관적인 방법으로, 이해하기 쉽다!

하지만, 순서가 변경되는 객체를 포함해 그 뒷 순서인 객체들의 order를 전부 Update해줘야한다는 단점이 있다.

2. order간의 간격을 크게 띄운다.

order간의 간격을 크게 잡는다.

아이템 리스트가 있을 때, 각 아이템들 순서(order)를 가지고 한 줄로 나열되어 있다고 해보자. order가 작을수록 앞에 위치한다.

nameorder
item11024
item22048
item33072

현재 아이템들은 item1 -> item2 -> item3의 순서로 되어있다. 표를 보면 각 아이템들의 order가 1024만큼 띄어진 것을 볼 수 있다.

item3의 위치가 item1item2의 사이로 변경되었다고 해보자. item1 -> item3 -> item2

이 때 item3의 order는 좌우에 위치하는 item1item2의 중간값인 1536으로 변경된다.

nameorder
item11024
item31536
item22048

아이템들의 order가 큰 간격을 두고 있으므로 순서가 변경된 item의 order만 업데이트하는 것이 가능하다.

  • 앞쪽에 삽입 시 가장 첫 레코드의 절반 부분에 삽입 -> order = round(min(order) / 2)
  • 뒤쪽에 삽입 시 가장 뒷 레코드의 절반 부분에 삽입 -> order = round(max_bigint - (max(order) / 2))
  • 가운데 삽입 시 앞 레코드와 뒤 레코드의 절반 부분에 삽입 -> order = round((before_order+after_order) /2)

이 방법은 하나의 item order값만 변경하면 된다는 장점이 있지만, 변경 로직이 아주 많이 발생할 경우 정확한 동작이 이루어지지않을 것이다. (각 order들의 간격이 점점 작아질 것이므로)

참고 링크

3. order를 소수로 표현한다.

order의 간격을 크게 띄우는 것과 동일한 원리이다.

소수를 이용해서, 앞에 올 컬럼의 순서보다 0.01 정도씩 높여서 이동시키는 방법이다. 하지만 float나 double은 정밀도에서 부족해서, 동일한 동작을 반복하다보면 오차가 생길 수 있다.

4. parent_id를 이용해서 앞에 올 아이템이 무엇인지 저장한다. (like linked list)

링크 리스트처럼, 순서가 변경된 item의 컬럼만 변경할 수 있다. 그러나 앞에서 나온 2, 3번 방법은 orderby order를 사용해 조회해올 수 있는 반면, linked list 방법은 parent_id 를 기준으로 join문을 수행해야할 필요가 있다.

WITH SortedList (Id, ParentId, SomeData, Level)
AS
(
  SELECT Id, ParentId, SomeData, 0 as Level
    FROM LinkedList
   WHERE ParentId IS NULL
  UNION ALL
  SELECT ll.Id, ll.ParentId, ll.SomeData, Level+1 as Level
    FROM LinkedList ll
   INNER JOIN SortedList as s
      ON ll.ParentId = s.Id
)

SELECT Id, ParentId, SomeData
  FROM SortedList
 ORDER BY Level

어떤 방법을 사용하는 게 좋을까?

전부 장단점이 있다! 아이템의 개수가 작다면, 1번의 방법으로 해도 성능에 큰 문제가 없을 것이다. (또는 배치 업데이트를 사용해서 쿼리 성능을 올리는 방법도 있을 것이다.)

하지만 아이템의 개수가 많다면, order의 간격을 크게 두거나 linked list처럼 구현하는 게 좋을 것 같다.

지금 프로젝트에서는 하나의 콘텐츠에 최대 20개의 아이템을 생성할 수 있는데, 그렇다면 아이템 순서 변경이 일어나도 최대 20개의 아이템들만이 업데이트 될 것이다. 그래서 순서가 바뀐 아이템들의 order를 전부 업데이트해주는 1번 방법을 선택했다. (나 왜 고민했지)

4개의 댓글

comment-user-thumbnail
2023년 7월 30일

오 멋진 방법이네요

1개의 답글
comment-user-thumbnail
2023년 8월 3일

잘봤습니다!

1개의 답글