0

我試圖在我的應用程序中實現像Trello這樣的看板敏捷板。我想知道如何以最好的方式做到這一點。我在考慮這些實體:KanBan數據庫體系結構


有很多解釋

列表
有許多卡


包含內容的

不過我米堅持訂購卡。每張卡都應該有一個排序位置,以便在列表中按特定順序排列卡片。拖動卡片時,我應該改變它的位置並將其保存在數據庫中。做這件事最有效的方法是什麼?

爲每張卡片添加一個position字段似乎是多餘的,因爲在將卡片拖到不同位置(將有數百張卡片)之後,我將不得不重新計算列表中的所有卡片的位置(或兩個)。我正在考慮將所有卡片ID的數組存儲在列表中,並按此數組排序卡片。這種解決方案的優點/缺點是什麼?有沒有更好的解決方案?

我正在使用Ruby on Rails和PostgreSQL。

UPDATE

使用@cske答案,我想出了以下解決方案:

CREATE OR REPLACE FUNCTION move_buyer_card(
    new_list_id INT 
    , param_id  INT 
    , new_position INT 
) RETURNS FLOAT4 
LANGUAGE plpgsql SECURITY DEFINER 
AS $$ 
DECLARE 
    var_lower_bound FLOAT4; 
    var_upper_bound FLOAT4; 
    var_new_weight FLOAT4; /*between 0 and 1*/ 
BEGIN 
    IF new_position < 2 THEN /*first position*/ 
    var_lower_bound := 0; 
    SELECT MIN(weight) FROM Buyers 
     WHERE board_list_id = new_list_id 
     INTO var_upper_bound; 
    IF var_upper_bound IS NULL THEN /*empty list*/ 
     var_upper_bound := 1; 
    END IF; 
    ELSE /*not first position*/ 
    WITH ordered_cards AS (
     SELECT id, RANK() OVER (ORDER BY weight ASC) AS rank, weight 
     FROM Buyers WHERE board_list_id = new_list_id 
    ) 
    SELECT cards0.weight, cards1.weight from ordered_cards cards0 
     JOIN ordered_cards cards1 
     ON cards0.rank = cards1.rank - 1 
     WHERE cards1.rank = new_position 
     INTO var_lower_bound, var_upper_bound; 
    IF NOT FOUND THEN /*only 1 item in list OR last position*/ 
     SELECT MAX(weight) FROM Buyers WHERE board_list_id = new_list_id 
     INTO var_lower_bound; 
     IF var_lower_bound IS NULL THEN /*empty list*/ 
     var_lower_bound := 0; 
     END IF; 
     var_upper_bound := 1; 
    END IF; 
    END IF; 
    var_new_weight := var_lower_bound + (var_upper_bound - var_lower_bound)/2; 
    UPDATE Buyers 
    SET weight = var_new_weight, 
     board_list_id = new_list_id 
    WHERE id = param_id; 
    RETURN var_new_weight; 
END; 
$$; 

回答

1

考慮這一點,招不存儲位置,但權重,因此您可以任意兩個之間插入元件

create table listOfCards (
    listId INTEGER 
    ,cardId INTEGER 
    ,weigth FLOAT4 
    ,PRIMARY KEY (listId,cardId) 
); 

CREATE OR REPLACE FUNCTION addCard(
    plistId INT 
    , pcardId INT 
    , ppos INT 
) RETURNS FLOAT4 
LANGUAGE plpgsql SECURITY DEFINER 
AS $$ 
DECLARE 
    vlb FLOAT4; 
    vub FLOAT4; 
    vnw FLOAT4; 
BEGIN 
    IF 2 > ppos THEN 
    vlb := 0; 
    SELECT min(weigth) FROM listOfCards WHERE listId = plistId INTO vub; 
    IF vub IS NULL THEN /*empty list*/ 
     vub := 2; 
    END IF; 
    ELSE 
    with corder as (select cardId,RANK() OVER (order by weigth asc) as r,weigth FROM listOfCards WHERE listId=1) 
    select c0.weigth,c1.weigth from corder c0 JOIN corder c1 ON c1.r = c0.r + 1 where c1.r = ppos INTO vlb,vub; 
    IF NOT FOUND THEN 
     SELECT max(weigth) FROM listOfCards WHERE listId = plistId INTO vlb; 
     IF vlb IS NULL THEN /*empty list*/ 
     vlb := 0; 
     END IF; 
     vub := (vlb+1) * 2; 
    END IF; 
    END IF; 
    vnw := vlb + (vub-vlb) /2; 
    INSERT INTO listOfCards(listId, cardId, weigth) 
     VALUES (plistId,pcardId,vnw) 
    ON CONFLICT ON CONSTRAINT listofcards_pkey DO UPDATE SET weigth = vnw ; 
    RETURN vnw; 
END; 
$$; 

用法:

select addCard(1,1,1); 
select addCard(1,2,1); 
select addCard(1,3,2); 
select addCard(1,4,2); 
select addCard(1,5,5); 
select addCard(1,5,2); 

select * from listOfCards ORDER BY weigth; 

結果: 1,2,0.5 1,5,0.5625 1,4,0.625 1,3,0.75 1,1,1

+0

謝謝您的回答。這是一個可行的解決方案。我用一個稍微修改過的代碼更新了我的問題 - 你能評論一下嗎?我認爲我的解決方案稍微簡單一點(不那麼令人困惑的數字)。 – leemour

+0

@leemour @leemour如果更簡單,只是使用它(你的代碼需要param_id已經在買方(最後更新)但不檢查它),不要忘記正確測試邊緣情況(空列表,移動到單個元素列表中, ...),表結構從問題中丟失很難說更多 – cske

+0

是的,我完全測試了我的版本對所有邊緣情況。您的解決方案將最後一個項目的權重設置爲1,然後添加一個項目將其權重設置爲大於1的值。您是否介意更新解決方案以解釋此問題以便我可以接受?我用'vub:= 1;','ON c1.r = c0.r + 1'替換了'vub:= 2;',其中'ON c0.r = c1.r - 1'和'vub:=(vlb +1)* 2;''vub:= 1' – leemour