如何创建和维护 couchDB/pcouchDB doc _id

How to create and maintain couchDB/pcouchDB doc _id's

我是 couchDB 的新手,我正在努力了解 doc _id 的用法。到目前为止,我阅读和学到的是,我应该生成一个 doc _id,这样我就可以将 B 树用于 Index/Maping。建议使用 Docuripouchdb/collate 等工具。 让一些代码说明一切:

    // define a docuri route
    Docuri.routes({
        ':type/:name/:created_at': 'list'
    });

    var doc = {}; 
        doc.name = 'Testname_1';
        doc.type = 'List';
        doc.created_at = Math.floor(Date.now() / 1000);
        doc.updated_at = Math.floor(Date.now() / 1000);
        doc._id = Docuri.list(doc);

console.log(doc');
// {
//    _id: "list/Testname_1/1433973431"
//     created_at: 1433973431
//     name: "Testname_1"
//     type: "list"
//     updated_at: 1433973431
// }

接下来,我将为具有以下 doc 结构的列表添加一些项目。

    // define a docuri route
    Docuri.routes({
        '/:list_id/:type/:item/:created_at': 'item'
    });

    var doc = {}; 
        doc.item = 'Item_1';
        doc.type = 'Item';
        doc.list_id = 'List/Testname_1/1433973431';
        doc.created_at = Math.floor(Date.now() / 1000);
        doc.updated_at = Math.floor(Date.now() / 1000);
        doc._id = Docuri.item(doc);

console.log(doc');
// {
//    _id: "List/Testname_1/1433973431/Item/Item_1/1433973431"
//     list_id: "List/Testname_1/1433973431"
//     created_at: 1433973431
//     item: "Item_1"
//     type: "Item"
//     updated_at: 1433973431
// }

第 1 题

对于较小的数据库来说,这是一个好的结构吗?

问题 2

(这让我很烦恼)假设我会使用列表 _id,例如 <a href="List/Testname_1/1433973431/">Testname_1</a>。现在,如果列表名称发生变化,我是否应该也更改列表 _id,然后更改相应项目中的所有 list_id

这对我来说似乎很奇怪,因为我通常不会更改数据库条目的 ID。

但另一方面,用户会期望 HMTL-Link 对应于他的新列表名。

也许有人可以将我推向正确的方向,如何管理和使用 couchDB 和 pouchDB 中的 _id

编辑

这是我读到的关于 UUID 的两个教程

Before deciding on using a random value as doc _id, read the section When not to use map reduce

Use domain specific document ids where possible. With CouchDB it is best practice to use meaningful ids.

http://docs.ehealthafrica.org/couchdb-best-practices/

In this example, you're getting all those "indexes" for free, each time a document is added to the database. It doesn't take up any additional space on disk compared to the randomly-generated UUIDs, and you don't have to wait for a view to get built up, nor do you have to understand the map/reduce API at all.

Of course, this system starts to get shaky when you need to search by a variety of criteria: e.g. all albums sorted by year, artists sorted by age, etc. And you can only sort strings – not numbers, booleans, arrays, or arbitrary JSON objects, like the map/reduce API supports. But for a lot of simple applications, you can get by without using the query() API at all.

Performance tip: if you're just using the randomly-generated doc IDs, then you're not only missing out on an opportunity to get a free index – you're also incurring the overhead of building an index you're never going to use. So use and abuse your doc IDs!

http://pouchdb.com/2014/05/01/secondary-indexes-have-landed-in-pouchdb.html

Docuri 是一个有趣的想法,我完全支持 CouchDB 技巧和 "hacks" 之类的,但请不要被它误导。这是一个技巧,有点像 "hack".

我基本上只有几个 policies/habits 文档 ids:

  • 它们是完全随机的且毫无意义(对于应用程序代码),尽管我经常严格地用它们的类型作为前缀 为了调试方便——任何需要知道文档的代码type 从 doc.type 或类似字段中获取,notdoc._id 中获取。所以我可能会调用一个文档 "photo-1qr333qew3qadeiof" 只是为了我可以在网络日志或其他东西中注意到它,但应用程序逻辑不会根据 id 假设任何东西。
  • 有时我需要确保相关文档的唯一性,例如 "user" 文档可能需要恰好(或至少不超过)一个相关"profile" 文件。或者,一个更好的例子,也许我想确保特定交易不超过一次:避免重复购买或其他。所以我取了一个 "tuple" 可能是用户 ID 和内容 ID,并通过 'txn-'+hash(username + song._id) 识别购买记录。然后,如果该特定组合再次意外发生,我将得到 409*,因为确定派生的 id。
  • 甚至更少,我有时会为一个应用程序制作特殊的 ID(想想一个名为 "SHARED_CONFIG" 或 "MY_APP_GLOBAL_COUNTER" 或其他东西的文档......)以便它可以在有限的情况下直接访问它们用于特定目的.

但要点是,默认情况下,您应该为您的文档使用某种 UUID,除非您有充分的理由不这样做。 CouchDB 仅在文档​​级别提供原子性这一事实意味着您可能会在文档 id 中添加更多含义(如在第二种情况下),另请参阅像 Docuri 这样的技巧,这种技巧将 id 用于 "optimize" 一些案例,但首先将它们视为 "meaningless but unique" 字符串。

您通常使用视图来处理基于文档内部数据的有意义的[二级]索引。 (是的,再次,您可以 use/abuse "primary" 索引,即数据库本身通过 _all_docs 在特殊情况下作为 optimization/trick/hack,但这不会是 正常练习。)

[*由于 its totally broken quorum handling,Cloudant 和 CouchDB 2.0 下最后一个案例的正确处理更加复杂,但这是一个不同的话题。]

我最终使用了两个帮助脚本,docuri and speakingurl

我的 "List" 数据库中的条目现在有一个新字段 slug。 首先,我使用 speakingUrl 从用户提供的列表名称创建一个 slug,然后使用 docuri 生成 _id 具有 slug 值。

docUri.routes({ ':type/:slug/:created_at': 'list' });

var slug = speakingUrl('My List Name is test');

var listObj = {};    
listObj.name = 'My List Name is test';
listObj.type = 'list';  
listObj.created_at = Math.floor(Date.now() / 1000);
listObj.updated_at = Math.floor(Date.now() / 1000);
listObj.slug = slug;  
listObj._id = docuri.list( listObj );

我的列表文档如下所示:

[
  {
    "id": "list/my-list-name-is-test/1436098113",
    "key": "list/my-list-name-is-test/1436098113",
    "value": {
      "rev": "1-d96c34ce1732e3e8088c4fa9d6e54c14"
    },
    "doc": {
      "name": "My List Name is test",
      "type": "list",
      "created_at": 1436098113,
      "updated_at": 1436098113,
      "slug": "my-list-name-is-test",
      "_id": "list/my-list-name-is-test/1436098113",
      "_rev": "1-d96c34ce1732e3e8088c4fa9d6e54c14"
    }
  }
]

在 p/couchDB { startkey: 'list', endkey: 'list\uffff' }

中按名称排序列表

通过此设置,我可以将 slug 字段用于列表 URL www.foo.bar/list/my-list-name-is-test。在目标页面上,我使用 URL slug 通过以下过滤器

查询列表项

{ startkey: 'item/' + URL_SLUG_VAR, endkey: 'item/' + URL_SLUG_VAR + '\uffff' }

我的物品文档是这样的:

[
  {
    "id": "item/my-list-name-is-test/This is the item Title/1436098113",
    "key": "item/my-list-name-is-test/This is the item Title/1436098113",
    "value": {
      "rev": "1-c023db010d075d6a9129288b0649554d"
    },
    "doc": {
      "Title": "This is the item Title",
      "type": "item",
      "created_at": 1436098113,
      "updated_at": 1436098113,
      "slug": "this-is-the-item-title",
      "_id": "item/my-list-name-is-test/This is the item Title/1436098113",
      "_rev": "1-c023db010d075d6a9129288b0649554d"
    }
  }
]

当用户现在更改列表名称值时,slug 应保持不变,因此对项目的查询应该有效。

此解决方案的缺点是,当用户更改 List Name 时,slug 不会更改,因此 URL 将保留它最初的创建方式。 这 恕我直言 不是最好的可用性,因为用户会期望他的列表的 URL 对应于新列表名称。

我还在考虑在 列表名称 更改时也更改相应的项目 _id。但是,考虑到数据库性能和设计,这种 "feels" 是错误的做法。

如果有人提出更好的解决方案或任何建议,请 post 他们。