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