【问题标题】:How to create and maintain couchDB/pcouchDB doc _id's如何创建和维护 couchDB/pcouchDB doc _id's
【发布时间】:2015-07-09 18:48:28
【问题描述】:

我对 couchDB 还很陌生,我正试图将自己的想法隐藏在 doc _id 的用法上。到目前为止,我阅读和了解到的是,我应该生成一个doc _id,这样我就可以将 B-tree 用于索引/映射。建议使用 Docuripouchdb/collat​​e 等工具。 让一些代码自己说话:

    // 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
// }

问题一

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

第二个问题

(这主要困扰我)假设我会使用列表 _id 就像 <a href="List/Testname_1/1433973431/">Testname_1</a> 一样。现在如果列表名称发生变化,我是否也应该更改列表_id,然后从相应的项目中更改所有list_id

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

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

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

编辑

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

在决定使用随机值作为 doc _id 之前,请阅读何时不使用 map reduce 部分

尽可能使用特定于域的文档 ID。对于 CouchDB,最佳实践是使用有意义的 id。

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

在此示例中,每次将文档添加到数据库时,您都可以免费获得所有这些“索引”。与随机生成的 UUID 相比,它不会占用任何额外的磁盘空间,而且您无需等待视图构建完成,也无需了解 map/reduce API。

当然,当您需要按各种条件进行搜索时,这个系统就会开始变得不稳定:例如所有专辑按年份排序,艺术家按年龄排序,等等。而且你只能对字符串进行排序——不能像 map/reduce API 支持的那样对数字、布尔值、数组或任意 JSON 对象进行排序。但是对于很多简单的应用程序,你可以完全不使用 query() API。

性能提示:如果您只是使用随机生成的文档 ID,那么您不仅会错失获得免费索引的机会,还会产生构建索引的开销永远不会使用。因此,请使用和滥用您的文档 ID!

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

【问题讨论】:

    标签: indexing couchdb pouchdb


    【解决方案1】:

    我最终使用了两个帮助脚本,docurispeakingurl

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

    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' }

    我的 Item 文档如下所示:

    [
      {
        "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 应该保持不变,因此对项目的查询应该可以工作。

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

    我仍在考虑在 列表名称 更改时也更改相应的项目_ids。但考虑到数据库性能和设计,这“感觉”是错误的做法。

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

    【讨论】:

      【解决方案2】:

      Docuri 是一个有趣的想法,我完全支持 CouchDB 技巧和类似的“黑客”,但请不要被它误导太多。这是一个技巧,有点像“黑客”。

      我基本上只有几个关于文档 ID 的政策/习惯:

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

      但重点是,默认情况下,您应该为您的文档使用某种 UUID,除非您有充分的理由不这样做。 CouchDB 仅在文档​​级别提供原子性这一事实意味着您可能会在文档 id 中添加更多含义(如在第二种情况下),并且还可以看到像 Docuri 这样的技巧使用 id 来“优化”某些情况,但首先将它们视为“无意义但唯一”的字符串。

      您通常使用视图来处理基于文档内部数据的有意义的[二级]索引。 (是的,同样,您可以在特殊情况下通过_all_docs 使用/滥用“主”索引,即数据库本身作为优化/技巧/黑客,但这不是正常的做法。 )

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

      【讨论】:

      • 感谢 natevw 的回答!我知道数据库中的 UUID,我来自 mysql 背景。我问的原因是我添加到我的问题中的两个教程。据我了解,我可以手动创建“索引/地图/视图”或使用“有意义的”UUID 自动创建它们并获得更好的性能并节省磁盘空间。
      猜你喜欢
      • 2011-03-14
      • 2010-11-21
      • 2010-12-27
      • 2017-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-17
      • 2012-04-06
      相关资源
      最近更新 更多