在CouchDB中生成自动递增数字ID的方法

时间:2011-02-22 02:11:12

标签: couchdb auto-increment

由于CouchDB不支持类似于SQL的AUTO_INCREMENT,您为文档生成顺序唯一数字ID的方法是什么?

修改

我需要数字ID,原因如下:

  • 用户友好的ID(例如TASK-123,RQ-001等)
  • 与需要数字主键的库/系统集成

我知道复制等问题。这就是为什么我对人们如何克服这个问题感兴趣。

6 个答案:

答案 0 :(得分:35)

正如Dominic Barnes所说,自动增量整数不可扩展,不适合分布式或云友好。现在似乎每个应用程序都需要具有离线支持的移动版本,并且它与自动增量整数不直接兼容。我们都知道这一点,但确实如此:遗留代码和其他东西都需要自动增量整数。

在这两种情况下,您都负责生成自动递增整数。视图正在运行emit(the_numeric_id, null)。 (你也可以有一个“类型”命名空间,例如emit([doc.type, the_numeric_id], null)。查询最后一行(例如用startkey=MAXINT&descending=true&limit=1,增加返回的值,这是你的下一个id。保存的尝试在一个循环中,如果发生碰撞,可以重试。

如果您不需要100%密度的ID列表,也可以玩技巧。例如,您可以将时间戳添加到emit()行,并估计文档创建速度,并按该速度乘以计算和传输时间。您也可以简单地增加1到N之间的随机整数,因此大多数情况下第一个插入都会起作用,代价是非同类ID号。

关于存储整数的位置,我认为存在 id 策略和尝试并检查策略。

id 策略在短期中更简单快捷。文档ID是一个整数(可能以添加命名空间的类型为前缀)。由于Couch保证_id字段的唯一性,您只需担心自动递增。在循环中执行此操作:409 Conflict触发重试,201 Accepted表示您已完成。

我认为这个诀窍的主要痛苦是,如果你发现冲突,你有两个完全不相关的文件,其中一个必须被复制到一份新文件。如果与其他文件存在关系,则必须全部纠正。 (想到CouchDB 0.11 emit(key, {_id: some_foreign_doc_id})技巧。)

尝试并检查策略使用默认UUID作为doc._id,因此每次插入都会成功。理想情况下,所有或大多数文档间关系都基于不可变的UUID _id,而不是整数。这只是用于用户和UI。自动递增整数只是文档{"int_id":20}中的一个字段。视图当然是emit(doc.int_id, null)。 (您可以按整数id查找文档,并使用视图的?key=23?include_docs=true参数。

当然,在复制之后,您可能会遇到ID冲突(不是官方的CouchDB冲突,而只是使用相同数字ID的文档)。按ID发出的视图也会有一个缩减阶段:简单_count就足够了。接下来,您必须巡视数据库,使用?group=true查询此视图并查找具有计数>的任何行(对应于整数ID)。 1.从好的方面来说,更正文档的数字ID是一个小改动,因为它不需要创建新的文档。

这些是我的想法。既然我把它们写下来了,我觉得你必须做关系牧养,无论id存储在哪里;所以或许最好使用_id。我看到的另一个缺点是,你永远与一个根本破坏的命名模型结合 - 对于“永久性”的某些定义。

答案 1 :(得分:3)

您是否有任何特殊原因想要使用CouchDB可以为您生成的UUID上的数字ID? UUID非常适合CouchDB使用的分布式范例,坚持内置的内容。

如果您发现自己的架构中有超过1个CouchDB节点,那么如果您在复制时依赖“自动增量”之类的东西,那么您将会遇到冲突的文档ID。即使您现在只使用1个节点,也可能并非总是如此,特别是因为CouchDB在分布式和“离线”架构中运行良好。

答案 2 :(得分:3)

我使用iso格式的日期作为我的关键字运气好了:

http://wiki.apache.org/couchdb/IsoFormattedDateAsDocId

这很简单,人类可读,它基本上只是存在一些查询选项。 : - )

答案 3 :(得分:1)

请记住有关复制和冲突的问题,您可以使用更新功能生成在单个主设置中保证唯一的递增ID。

function(doc, req) {
    if (!doc) {
        doc = {
            _id: req.id,
            type: 'idGenerator',
            count: 0
        };
    }
    doc.count++;
    return [doc, toJSON(doc.count)];
}

将此功能包含在设计文档中,如下所示:

{
   "_id": "_design/application",
   "language": "javascript",
   "updates": {
       "generateId": "function (doc, req) {\n\t\t\tif (!doc) {\n\t\t\t\tdoc = {\n\t\t\t\t\t_id: req.id,\n\t\t\t\t\ttype: 'idGenerator',\n\t\t\t\t\tcount: 0\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tdoc.count++;\n\t\t\t\n\t\t\treturn [doc, toJSON(doc.count)];\n\t\t}"
   }
}

然后这样称呼它:

curl -XPOST http://localhost:5984/mydb/_design/application/_update/generateId/entityId

entityId替换为您想要的任何内容,以创建多个独立的ID序列。

答案 4 :(得分:0)

您可以使用couchDB接受的隐式索引进行分页,而不是显式构造增量整数键。

skip 参数接受一个有效提供您习惯的自动递增索引的整数。

http://wiki.apache.org/couchdb/HTTP_view_API#Querying_Options

缺点是它不是用户友好ID和#34;的可行解决方案。该索引与文档无关,如果您正在重写历史记录,则可能会发生变化。

如果你的唯一约束是"与需要数字主键的#/;系统/系统的集成,这将弥补差距而不会失去couchDB的关键结构的好处。

答案 5 :(得分:0)

不是一个完美的解决方案,但对我有用的东西。创建一个生成自动递增的ID的独立服务。是的,你可能会说“这打破了couchdb的离线模型”但是如果你得到一个N ID池,那么只要你需要获得一个新的自动增量id就可以使用它。然后,每当你在线时,你会得到更多的ID,如果你的ID太少,你就会告诉你的用户 - 请上网。如果游泳池足够大(比如月流量),这不应该发生。再一次,不完美,但可能对某些人有帮助。