我知道这种情况违背了关系数据库的原则,但让我来描述一下情况.
我有一个页面,用户将放置一些项目.
________________
| -Item1 |
| -Item2 |
| -Item3 |
| -Item4 |
|________________|
Run Code Online (Sandbox Code Playgroud)
这些项目必须保持用户给出的顺序.然而,用户可以将该顺序改变任意次数.
________________
| -Item1 |
| -Item4 |
| -Item2 |
| -Item3 |
|________________|
Run Code Online (Sandbox Code Playgroud)
方法1
我最初的想法是给项目一个索引来代表列表中的位置
Page Item
----------- ---------------
FK | pid FK | pid
| name PK | iid
| index
| content
Run Code Online (Sandbox Code Playgroud)
使用此解决方案,您可以选择项目where pid = Page.pid,order by index方便.但是,每次更改订单时,您必须在另一个项目(最佳案例)和所有其他项目(最差情况)之间进行任何更改.
方法2
我还考虑制作一个"链表",如数据结构,其中每个项指向列表中的下一个项.
Page Item
----------- ---------------
FK | pid FK | pid
| name PK | iid
| …Run Code Online (Sandbox Code Playgroud) 我正在使用 CouchDB/PouchDB 构建可以被视为幻灯片应用程序的东西:每个“幻灯片”都是它自己的 Couch 文档,幻灯片可以重新排序或删除,并且可以在现有幻灯片之间或在开头或幻灯片结束。一个幻灯片可以从一张幻灯片增加到 10,000 张幻灯片,所以我对空间和时间效率很敏感。
我首先制作了幻灯片创建/编辑功能,完全低估了跟踪幻灯片排序的难度。这很难,因为每个幻灯片文档的顺序完全独立于幻灯片文档本身,也就是说,我无法按时间或文档中包含的某个数字对其进行排序。我在 StackOverflow 上看到了许多关于如何跟踪关系数据库中的排序的问题:
但所有这些都涉及
previous和next字段,其中包含文档的任一侧的主键;这些都不适合 CouchDB:#1 在 SQL 或 CouchDB 中会产生大量的偶然复杂性。#2 不可靠,因为缺乏原子事务(CouchDB 可能会用它的新文档更新前一个文档,next但同时另一个客户端可能已经更新了新的下一个文档,因此更新新的下一个文档将失败并显示 409,并且您的链表被保留在不一致的状态)。出于同样的原因,#3 是完全行不通的。
我正在评估的一种面向 CouchDB 的方法将创建一个仅包含幻灯片排序的文档:它可能包含一个主键到订单号的哈希对象以及一个将订单号转换为-的数组主键,并在幻灯片重新排序/插入/删除时更新此对象。这样做的缺点是 Couch 会为每次订单更改(重新排序/插入/删除)保留一份这个潜在大文档的副本——CouchDB 不支持压缩单个文档,我不想在我的文件上运行压缩整个数据库,因为我喜欢保留每个幻灯片文档的历史记录。另一个缺点是,在数千张幻灯片之后,每次对排序的更改都涉及将整个对象(数百 KB)从 PouchDB/客户端传输到 Couch。
这种方法的一个调整是创建第二个数据库来保存这个订购文档并打开它的自动压缩。跟踪两个数据库连接需要做更多的工作,而且我最终必须将大量数据放到网络上,但我将有一种强大的方式来在 CouchDB 中订购文档。
所以我的问题是:CouchDB 人们通常如何存储文档的顺序?更有经验的 CouchDB 人员能否看到我上面概述的方法中的任何缺陷?