我正在开发一个本质上与待办事项列表非常相似的应用程序,除了待办事项的顺序很重要并且可以由用户更改。
有什么好方法可以将此订单保存在数据库中,而无需在更改订单时重新保存整个待办事项列表?
我正在使用最新版本的 Rails、Postgres 和 React 进行开发。
我正在考虑将它保存为 User Todos 中的一个数组(应用程序可以有多个用户),但我认为它可能会使事情变得有点复杂,因为每次我创建一个 todo 时我都必须保存列表。
我正在开发一个本质上与待办事项列表非常相似的应用程序,除了待办事项的顺序很重要并且可以由用户更改。
有什么好方法可以将此订单保存在数据库中,而无需在更改订单时重新保存整个待办事项列表?
我正在使用最新版本的 Rails、Postgres 和 React 进行开发。
我正在考虑将它保存为 User Todos 中的一个数组(应用程序可以有多个用户),但我认为它可能会使事情变得有点复杂,因为每次我创建一个 todo 时我都必须保存列表。
您可以查看acts_as_list gem,为此您必须在表中添加一个额外的列位置。但这将对记录进行大规模更新。但是这个宝石经常更新。
如果您想要一个优化的解决方案并尽量减少更改列表的更新次数,那么您应该检查ranked_model gem,但这个不是经常更新。有一个关于它是如何工作的简介: -
这个库是从头开始使用 ARel 编写的。这使代码比许多实现更干净。rank-model 还优化为尽可能少地写入数据库:rank 存储为介于 -2147483648 和 2147483647 之间的数字(MySQL 中的 INT 范围)。当一个项目被赋予一个新位置时,它会在两个邻居之间为自己分配一个排名号。这允许在两个邻居之间没有可用的数字之前进行项目的多次移动。发生这种情况时,ranked-model 将尝试将其他记录移开。如果项目不能再轻易移动,它将重新平衡排名组所有成员的排名数字分布。
您可以参考此 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)
请注意,在此表中插入时,在值之间留出间隙会更有效,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;
上面将ord
from1,2,3,4,5,10,11
重新编号为1,2,3,5,6,10,11
在 4 处留下一个洞。如果在ord
=4 处已经有一个洞,则上面的查询不会做任何事情。
然后通过给它现在的自由ord
值 4 来插入或移动另一行。
您可以通过将 +1 更改为 -1 来向下而不是向上推动行。