CouchDB/PouchDB 中的任意文档排序

Arbitrary document ordering in CouchDB/PouchDB

我正在使用 CouchDB/PouchDB 构建可被视为幻灯片应用程序的应用程序:每张“幻灯片”都是其自己的 Couch 文档,可以重新排序或删除幻灯片,并且可以在其间添加新幻灯片现有幻灯片或在幻灯片的开头或结尾。一个幻灯片可以从一张增加到 ≲10,000 张幻灯片,所以我对 space- 和时间效率很敏感。

我首先制作了幻灯片 creation/editing 功能,完全低估了跟踪幻灯片排序的难度。这很难,因为每个幻灯片文档的顺序完全独立于幻灯片文档本身,也就是说,我无法按时间或文档中包含的某些数字进行排序。我在 Whosebug 上看到许多关于如何跟踪关系数据库中的顺序的问题:

但所有这些都涉及

  1. 为 reordering/creation/deletion 使用浮点辅助键,并定期规范化索引(即假设两个文档的顺序索引为 1.0 和 2.0,然后中间的第三个文档获得键 1.5,然后是第四个得到 1.25,…,直到在中间插入了 ~31 个文档,你会遇到浮点精度问题);
  2. 一种链表方法,其中幻灯片文档有一个 previousnext 字段,其中包含其两侧的文档主键;
  3. 为每个文档更新所有文档的一种非常直接的方法reordering/insertion/deletion。

None 其中适合 CouchDB:#1 在 SQL 或 CouchDB 中会产生大量附带的复杂性。 #2 由于缺少原子事务而不可靠(CouchDB 可能会用新的 next 更新前一个文档,但另一个客户端可能同时更新了新的下一个文档,因此更新下一个新文档将失败并显示 409,并且您的链表处于不一致状态)。同理,#3也是完全行不通的。


我正在评估的一种面向 CouchDB 的方法将创建一个仅包含幻灯片排序的文档:它可能包含一个主键到订单号的哈希对象以及一个转换顺序的数组-number-to-primary-key,并在幻灯片 reordered/inserted/deleted 时更新此对象。这样做的缺点是 Couch 会为每次订单更改保留一份这个可能很大的文档的副本 (reorder/insert/delete)—CouchDB 不支持仅压缩单个文档,我不想 运行 对我的整个数据库进行压缩,因为我喜欢保留每个幻灯片文档的历史记录。另一个缺点是,在数千张幻灯片之后,每次更改顺序都涉及将整个对象(数百千字节)从 PouchDB/client 传输到 Couch。

对此方法的一个调整是创建第二个数据库来保存此订购文档并在其上打开自动压缩。跟踪两个数据库连接会带来更多工作,最终我将不得不传输大量数据,但我将拥有一种在 CouchDB 中订购文档的稳健方式。


所以我的问题是:CouchDB 人们通常如何存储文档的顺序?更有经验的 CouchDB 人员能看出我上述方法中的任何缺陷吗?

根据我阅读的内容,我会选择 "ordering document" 方法。 (即:每个幻灯片文档都有一个 id 数组的幻灯片文档)这非常简单并且完成了用例,所以我不会让这些问题妨碍 clean/intuitive 代码。

你是对的,这个文档可能会变得非常大,加上该特定文档的写入量大的性质。这就是压缩存在的原因,也是这里的解决方案,所以你不应该在这一点上与 CouchDB 作对。

一个常见的误解是您可以使用 CouchDB 的修订历史记录来保存数据库的全面历史记录。这些修订只是为了帮助写并发, 而不是 作为一个完整的版本控制系统。

CouchDB 默认启用了自动压缩,如果没有它,您的数据库的大小将不受控制地增长。因此,您应该放弃使用这种方法跟踪文档历史记录的想法,而采用另一种更安全的替代方法。 (这些备选方案的列表超出了此答案的范围)

感谢@LynHeadley 的提示,我最终编写了一个可以细分字符串之间的字典间隔的库:Mudder.js。这使我可以通过随意创建新键,在 CouchDB 中无限地插入和移动文档,而无需任何辅助文档的开销来存储排序。我认为这是解决这个问题的正确方法!