database-design - 如何移动排序列表中的元素并保持 CouchDb 写入 "atomic"

标签 database-design data-structures transactions couchdb atomicity

我在 couchdb 文档中有一个列表元素。假设这些是 3 个文档中的 3 个元素:

{ "id" : "783587346", "type" : "aList", "content" : "joey", "sort" : 100.0 }
{ "id" : "358734ff6", "type" : "aList", "content" : "jill", "sort" : 110.0 }
{ "id" : "abf587346", "type" : "aList", "content" : "jack", "sort" : 120.0 }

View 检索所有“aList”文档并按“sort”排序显示它们。

现在我想移动元素,当我想将“jack”移动到中间时,我可以在一次写入中完成这个原子并将其排序键更改为 105.0.0。该 View 现在以新的排序顺序返回文档。

经过大量排序后,我可能会在几年后得到像 50.99999 和 50.99998 这样的排序键,并且在极端情况下会用完数字?

你能推荐什么,有没有更好的方法来做到这一点?我宁愿将元素保存在单独的文档中。不同的用户可能会并行编辑不同的列表元素。

并且用户也可能同时更改文档顺序(当 2 个用户想要将两个不同的文档(如 joey 和 jill)移动到末尾时,例如“sort” = 130.0,这也会变得棘手)。

也许有更好的方法?

我是否错过了 CouchDb 交易中的某些内容?

最佳答案

您正在使用实数的常见模式进行排序的用户控制。
这是一项很好的技术,由 Damien Katz 推荐。在相邻文档之间移动 AB ,然后你设置你的 sort场的平均值 A.sortB.sort .

这个问题有几个部分。

浮点精度怎么样?

Javascript Number s 是 double IEEE-754 浮点数。他们
精度有限。

double 精度很高。如果这是人类发起的事件,那么它
拖放操作将需要很长时间才能达到极限。
但是你有两个选择:

1.在后台重新归一化排序值

还记得用 BASIC 重写你的行号吗?一样。

有一份 cron 工作或其他一些任务(NodeJS 越来越受欢迎)
检查 Not Acceptable 接近排序值并将它们隔开。这个
可以使用复杂的启发式方法,例如:

  • 等到站点事件量较低时修复 sort s
  • 等到特定用户不事件 X 时间后再修复他的 sort s
  • 只做空间之外的修改sort值(value),但永远不会改变
    查看结果。换句话说,如果您有 0.001 , 0.002 , 和 0.003 ,
    移动 0.003首先到例如0.100 ,然后更改 0.0020.005 .那
    可能对 UI 有一点帮助,但请记住,复制可能不会
    以相同的顺序复制这些,所以好处是微不足道的,也许不值得
    复杂性。

  • 2. 使用具有无限精度的十进制数据类型

    而不是 sort存储 Javascript Number ,它可以存储一个字符串
    但不包括 "0.0"通过 "1.0" (比如说,到 100 位数字)。那么一个字符串排序是
    也是数字排序。 (您在 0.0 和 1.0 处有对文档无效的“ anchor ”。要在第一个位置插入文档,请将 sort 设置为 0.0 和当前第一个文档的平均值。对于最后一个位置,sort 是最后一个文档的平均值和 1.0。)

    接下来,您的客户(计算 sort 值的人)需要
    任意精度实数类型。 Java、Ruby、Python,几乎所有
    语言有它们。这篇文章甚至激励我做一个快速的项目,
    BigDecimal for Javascript这是 BigDecimal代码来自 Google Web Toolkit(它本身来自 Apache Harmony)。但是有
    也是其他实现。

    我个人喜欢 BigDecimal .但是,在您的情况下,您将不得不更改您的
    sort 使用字符串的代码.然而好处是,你永远不必重新规范化sort s 解决精度问题。

    来自并发事件的冲突呢?

    CouchDB 是放松的。将会发生什么是用户所期望的。沙发数据库
    文档模仿现实世界。正如克里斯·安德森所说,“没有
    现实生活中的交易。”

    对于 UI 中的三个元素:
  • 货品A
  • 项目B
  • 项目C

  • 如果我搬家怎么办 A之后 C你搬家B在 C 之后?显然,该列表要么是C B AC A B .应该是哪个?这取决于您的应用程序?

    要么,没关系 : 伟大的! CouchDB 将订购 AB随意而你
    会没事的。用户会推断(或查看您的 UI 是否良好)其他人移动了
    另一个项目。

    或者, B 必须在 A 之前,因为 [某些原因] : 那么,你的 sort值不对。
    它应该包括所有相关数据来决定子分类。例如,您可以emit([120.000, doc.userLastName], doc) .当用户将文档移动到同一位置时,
    sort 按字母顺序排列。

    如果你说, B 搬家后 A 不能这么快搬家 那么这也是应用
    无论数据存储如何,都必须实现的代码。换句话说,它不是
    一个事务性的东西,它是软件逻辑。对于拖放 UI 元素,
    我的感觉是,这不值得,“没关系”的解决方案是最好的。

    关于database-design - 如何移动排序列表中的元素并保持 CouchDb 写入 "atomic",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2940329/

    相关文章:

    sql - 如何在关系数据库中存储自定义实体属性

    python - Heapq模块实现

    sql - 在事务中使用显式提交

    php - 如何在 Nermalization 中跟踪更改和存储计算内容?

    database - MS Access 的实体关系图

    sql-server - 引用表是否应该包含数字 PK 标识列值 0?

    c - RPN中运算符的优先级

    c - C中具有动态数据类型的模块化数据结构

    jakarta-ee - EJB 中如何管理 CMT 和 BMT?

    transactions - Sybase 锁定策略