【发布时间】:2016-12-31 16:39:32
【问题描述】:
我正在使用 CouchDB/PouchDB 构建可以被视为幻灯片应用程序:每张“幻灯片”都是它自己的 Couch 文档,可以重新排序或删除幻灯片,并且可以在现有幻灯片之间或添加新幻灯片幻灯片的开头或结尾。幻灯片可以从 1 张增加到 ≲10,000 张幻灯片,因此我对空间和时间效率很敏感。
我首先制作了幻灯片创建/编辑功能,完全低估了跟踪幻灯片顺序的难度。这很难,因为每个幻灯片文档的顺序完全独立于幻灯片文档本身,也就是说,它不是我可以按时间或文档中包含的某个数字排序的东西。我在 StackOverflow 上看到了很多关于如何在关系数据库中跟踪排序的问题:
- Efficient way to store reorderable items in a database
- What would be the best way to store records order in SQL
- How can I reorder rows in sql database
- Storing item positions (for ordering) in a database efficiently
- How to keep ordering of records in a database table
- Linked List in SQL
但所有这些都涉及
- 使用浮点辅助键进行重新排序/创建/删除,并定期对索引进行标准化(即,假设两个文档的排序索引为 1.0 和 2.0,然后中间的第三个文档获取键 1.5,然后第四个获取1.25,...,直到在其中插入约 31 个文档,您会遇到浮点精度问题);
- 一种链表方法,其中幻灯片文档有一个
previous和next字段,其中包含其两侧文档的主键; - 一种非常简单的方法,可以为每个文档重新排序/插入/删除更新所有文档。
这些都不适合 CouchDB:#1 在 SQL 或 CouchDB 中会带来大量附带的复杂性。 #2 由于缺少原子事务而不可靠(CouchDB 可能会使用其新的next 更新上一个文档,但另一个客户端可能同时更新了新的下一个文档,因此更新新的下一个文档将失败并显示 409,并且您的链接列表处于不一致的状态)。出于同样的原因,#3 完全行不通。
我正在评估的一种面向 CouchDB 的方法将创建一个仅包含幻灯片排序的文档:它可能包含一个主键到订单号哈希对象以及一个转换订单号的数组-to-primary-key,并在幻灯片重新排序/插入/删除时更新此对象。这样做的缺点是,Couch 会为每个订单更改(重新排序/插入/删除)保留这个可能很大的文档的副本——CouchDB 不支持仅压缩单个文档,我不想在我的整个数据库,因为我喜欢保留每个幻灯片文档的历史记录。另一个缺点是,在数千张幻灯片之后,对排序的每次更改都涉及将整个对象(数百 KB)从 PouchDB/客户端传输到 Couch。
对这种方法的一个调整是创建第二个数据库来保存这个排序文档并打开它的自动压缩。跟踪两个数据库连接会做更多的工作,而且我最终必须将大量数据传输到网络中,但我将有一种强大的方式在 CouchDB 中排序文档。
所以我的问题是:CouchDB 人通常如何存储文档的顺序?更有经验的 CouchDB 人员能否发现我上述方法中的任何缺陷?
【问题讨论】:
-
@LynHeadley 对此表示感谢——我正在开发 m69’s answer 的超级版本,我认为这与 CouchDB 对查询上一个/下一个主 ID 的良好支持非常有效!
-
太棒了!我也一直在思考这个问题,并没有在网上找到任何好的答案。也许我们正在做点什么……
-
@LynHeadley 我认为使用一个接受两个字符串并返回一个按字典顺序在它们之间排序的字符串(理想情况下接近它们的“中点”)的函数可以解决问题。 m69 提供了这样的代码,我只是让它变得更好一些(base-62 将为大量文档提供非常短的密钥)。这很容易进行插入。移动文档会不太优雅:将文档复制到新的主键(按字典顺序在新邻居之间),然后删除旧的主键。没有大文件来跟踪订单,很好地利用了 CouchDB 的敏感性……还是我错过了什么?
-
@LynHeadley 花了一些时间,但我总结了那个库,概括了@m69 的答案,它工作得很好!查看我的回复stackoverflow.com/a/44448718/500207