如何实现todos/list的顺序保存?

How to implement saving of order of todos / list?

我正在开发一个在性质上与待办事项列表非常相似的应用程序,除了待办事项的顺序很重要并且可以由用户更改。

有什么好方法可以在数据库中保存此订单,而无需在更改订单时重新保存整个待办事项列表?

我正在使用 Rails、Postgres 和 React,最新版本进行开发。

我正在考虑将它保存为用户待办事项中的一个数组(应用程序可以有多个用户),但我认为这会使事情变得有点复杂,因为每次我创建一个待办事项时我都必须保存列表也。

您可以查看 acts_as_list gem,为此您必须在 table 中添加一个额外的列位置。但这将对记录进行大量更新。但是这个gem经常更新

如果您想要一个优化的解决方案并尽量减少更改列表时的更新次数,那么您应该检查 ranked_model gem,但这个不会经常更新。关于它的工作原理有一个简短的介绍:-

This library is written using ARel from the ground-up. This leaves the code much cleaner than many implementations. ranked-model is also optimized to write to the database as little as possible: ranks are stored as a number between -2147483648 and 2147483647 (the INT range in MySQL). When an item is given a new position, it assigns itself a rank number between two neighbors. This allows several movements of items before no digits are available between two neighbors. When this occurs, ranked-model will try to shift other records out of the way. If items can't be easily shifted anymore, it will rebalance the distribution of rank numbers across all members of the ranked group.

您可以参考此 gem 并制作您自己的实现,因为它仅支持 rails 3 和 4。

这有点让人头疼,但这是我的想法:

create table orderedtable (
   pk SERIAL PRIMARY KEY,
   ord INTEGER NOT NULL,
   UNIQUE(ord) DEFERRABLE INITIALLY DEFERRED
)

DEFERRABLE INITIALLY DEFERRED 很重要,这样中间状态就不会在重新排序期间导致约束违规。

INSERT INTO orderedtable (ord) VALUES (1),(2),(3),(4),(5),(10),(11)

请注意,在此 table 中插入时,在 ord 值之间留有间隙会更有效,以便最大限度地减少插入或移动行时需要移动的顺序值的数量之后。连续值用于演示目的。

技巧如下:您可以使用递归查询找到从特定值开始的连续值序列。

例如,假设您想在位置 3 的正上方插入或移动一行。一种方法是将当前位于位置 4 和 5 的行向上移动一个以打开位置 4。

WITH RECURSIVE consecutives(ord) AS (
  SELECT ord FROM orderedtable WHERE ord = 3+1 --start position
UNION ALL
  SELECT orderedtable.ord FROM orderedtable JOIN consecutives ON orderedtable.ord=consecutives.ord+1 --recursively select rows one above, until there is a hole in the sequence
)
UPDATE orderedtable
SET ord=orderedtable.ord+1
FROM consecutives
WHERE orderedtable.ord=consecutives.ord;

以上将 ord1,2,3,4,5,10,11 重新编号为 1,2,3,5,6,10,11,在 4 处留下一个洞。 如果 ord=4 已经有一个洞,上面的查询就不会做任何事情。

然后只需插入或移动另一行,方法是给它现在可用的 ord 值 4。

您可以通过将 +1 更改为 -1 来向下而不是向上推动行。