Ruby on rails 看板数据库体系结构
我正试图在我的应用程序中实现一个类似Trello的看板敏捷板。我想知道怎样才能做到最好。我正在考虑这些实体: 董事会 有许多清单 名单 他有很多卡片 卡片 包含一些内容 然而,我一直在订购卡片。每张卡片都应该有一个排序位置,以便按照列表中的特定顺序对卡片进行排序。当拖动卡片时,我应该更改它的位置并将其保存在数据库中。最有效的方法是什么 在每张卡上添加一个位置字段似乎是多余的,因为在我将一张卡拖到另一个位置后,我必须重新计算一两张列表中所有卡的位置,将有数百张卡。我正在考虑在一个列表中存储一个包含所有卡ID的数组,并根据该数组对卡进行排序。此解决方案的优点/缺点是什么?还有更好的解决方案吗 我正在使用RubyonRails和PostgreSQL 更新 使用@cske answer,我想出了以下解决方案:Ruby on rails 看板数据库体系结构,ruby-on-rails,postgresql,architecture,application-design,kanban,Ruby On Rails,Postgresql,Architecture,Application Design,Kanban,我正试图在我的应用程序中实现一个类似Trello的看板敏捷板。我想知道怎样才能做到最好。我正在考虑这些实体: 董事会 有许多清单 名单 他有很多卡片 卡片 包含一些内容 然而,我一直在订购卡片。每张卡片都应该有一个排序位置,以便按照列表中的特定顺序对卡片进行排序。当拖动卡片时,我应该更改它的位置并将其保存在数据库中。最有效的方法是什么 在每张卡上添加一个位置字段似乎是多余的,因为在我将一张卡拖到另一个位置后,我必须重新计算一两张列表中所有卡的位置,将有数百张卡。我正在考虑在一个列表中存储一个包含
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;
$$;
考虑到这一点,技巧不是存储位置,而是一个权重,以便可以在任意两个元素之间插入
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
谢谢你的回答。这是一个有效的解决方案。我用稍微修改过的代码更新了我的问题-你能对此发表评论吗?我认为我的解决方案稍微简单一些,不容易混淆的数字。@leemour如果更简单,就使用它。您的代码要求参数id在最后更新时已经存在,但不检查它,不要忘记正确地测试边缘案例空列表,移入单元素列表,…,问题中缺少表结构。很难说清楚是的,我针对所有edge案例对我的版本进行了全面测试。您的解决方案将最后一个项目的权重设置为1,然后添加一个项目将其权重设置为大于1的值。您是否介意更新您的解决方案以说明这一点,以便我可以接受?I替换vub:=2;当vub:=1时;,ON c1.r=c0.r+1,ON c0.r=c1.r-1,vub:=vlb+1*2;有vub时:=1