【问题标题】:KanBan Database architecture看板数据库架构
【发布时间】:2017-04-12 01:26:28
【问题描述】:

我正在尝试在我的应用程序中实现像 Trello 这样的看板敏捷板。我想知道如何以最好的方式做到这一点。我正在考虑这些实体:

董事会
有很多列表

列表
有很多卡

卡片
包含一些内容

但是,我坚持订购卡片。每张卡片都应该有一个排序位置,以便在列表中按特定顺序对卡片进行排序。拖动卡片时,我应该更改它的位置并将其保存在数据库中。最有效的方法是什么?

为每张卡片添加position 字段似乎是多余的,因为在将卡片拖动到不同位置(将有数百张卡片)后,我必须重新计算列表(或两个)中所有卡片的位置。我正在考虑将所有卡片 ID 的数组存储在列表中,并按此数组对卡片进行排序。该解决方案的优点/缺点是什么?有没有更好的解决方案?

我正在使用 Ruby on Rails 和 PostgreSQL。

更新

使用@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;
$$;

【问题讨论】:

    标签: ruby-on-rails postgresql architecture application-design kanban


    【解决方案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

    【讨论】:

    • 感谢您的回答。这是一个可行的解决方案。我用稍微修改的代码更新了我的问题 - 你能对此发表评论吗?我认为我的解决方案稍微简单一些(不那么混乱的数字)。
    • @leemour 如果这更简单,只需使用它(您的代码要求 param_id 已经在买家中(最后更新)但不检查它),不要忘记正确测试边缘案例(空列表,移入单个元素列表,...),问题中缺少表格结构,很难说更多
    • 是的,我针对所有边缘情况对我的版本进行了全面测试。您的解决方案将最后一个项目的权重设置为 1,然后添加一个项目会将其权重设置为大于 1 的值。您介意更新您的解决方案以解决这个问题,以便我可以接受吗?我用vub := 1;替换了vub := 2;,用ON c0.r = c1.r - 1替换了ON c1.r = c0.r + 1,用vub := 1替换了vub := (vlb+1) * 2;
    • @cske 大家好,这个话题对我来说非常棒。我只是想知道我们是否有 10000 张卡片 => 如果我们仍然使用重量来订购卡片可以吗?我担心数据类型“float”?
    猜你喜欢
    • 1970-01-01
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    相关资源
    最近更新 更多