【问题标题】:Arbitrary document ordering in CouchDB/PouchDBCouchDB/PouchDB 中的任意文档排序
【发布时间】:2016-12-31 16:39:32
【问题描述】:

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

我首先制作了幻灯片创建/编辑功能,完全低估了跟踪幻灯片顺序的难度。这很难,因为每个幻灯片文档的顺序完全独立于幻灯片文档本身,也就是说,它不是我可以按时间或文档中包含的某个数字排序的东西。我在 StackOverflow 上看到了很多关于如何在关系数据库中跟踪排序的问题:

但所有这些都涉及

  1. 使用浮点辅助键进行重新排序/创建/删除,并定期对索引进行标准化(即,假设两个文档的排序索引为 1.0 和 2.0,然后中间的第三个文档获取键 1.5,然后第四个获取1.25,...,直到在其中插入约 31 个文档,您会遇到浮点精度问题);
  2. 一种链表方法,其中幻灯片文档有一个 previousnext 字段,其中包含其两侧文档的主键;
  3. 一种非常简单的方法,可以为每个文档重新排序/插入/删除更新所有文档。

这些都不适合 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

标签: database couchdb pouchdb


【解决方案1】:

根据我所阅读的内容,我会选择“订购文件”方法。 (即:幻灯片文档,每个幻灯片文档都有一个 id 数组)这真的很简单并且完成了用例,所以我不会让这些问题妨碍干净/直观的代码。

您说得对,该文档可能会变得非常大,而且该特定文档的写入量很大。这就是为什么存在压缩并且是这里的解决方案,所以你不应该在这一点上与 CouchDB 对抗。

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

默认情况下,CouchDB 启用了自动压缩,如果没有它,您的数据库将在未经检查的情况下增长。因此,您应该放弃使用这种方法跟踪文档历史记录的想法,而采用另一种更安全的替代方法。 (这些替代方案的列表超出了此答案的范围)

【讨论】:

  • 当您说“CouchDB 默认启用自动压缩”时,您的意思是_revs_limit option,默认为 1000,即 CouchDB 将保留不超过 1000 个修订? 1000 仍然很多!所以自动压缩(在每次写入后立即丢弃非叶节点)是否仍然很重要——因此需要第二个数据库?
  • 拜托,非常拜托,如果 Couch 的修订系统不提供它,您能否评论或指出 CouchDB 之上(或更高版本)上的“适当”版本控制 ?? (我打算将它用作一个非常温和的“撤消”系统,在发生灾难时,我至少可以阅读旧版本的文档,但是您的 cmets 在这些方面让我认为我不应该期望能够做到那个。)
  • 我会阅读他们关于压缩的文档,特别是automatic compaction的这一部分
  • 至于其他问题,我将简单地向您推荐我回答的另一个问题:stackoverflow.com/a/28357763/188702
  • 谢谢。 wiki.apache.org/couchdb/How_to_design_for_replication 也有助于理解处理语义更新的策略。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多