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

时间:2015-06-10 23:42:32

标签: indexing couchdb pouchdb

我对couchDB很新,我试图将我的想法包含在doc _id的用法之后。到目前为止我读到和学到的是,我应该生成一个doc _id,这样我就可以使用B树进行索引/映射。建议使用 Docuri pouchdb / 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
// }

问题1

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

问题2

(这主要是我的错误)让我说我会像_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。< / p>      

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

     

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

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

2 个答案:

答案 0 :(得分:1)

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

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

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

中对列表进行排序

通过此设置,我可以使用列表URL www.foo.bar/list/my-list-name-is-test 的slug字段。在目标页面上,我使用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应该保持不变,因此对项目的查询应该有效。

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

列表名称更改时,我仍在考虑更改相应的项目_id。但这种“感觉”似乎是考虑到数据库性能的错误方式。设计。

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

答案 1 :(得分:0)

Docuri是一个有趣的想法,我全都是CouchDB技巧和&#34; hacks&#34;像这样,但请不要被它误导。这是一个技巧,它是一个&#34; hack&#34;。

我基本上只有一些政策/习惯与文件ID:

  • 它们完全是随机的,没有意义(对于应用程序代码),虽然我经常在它们的类型前面加上严格的以便于调试 - 任何需要知道文档类型的代码都是从来自doc.type的{​​{1}}或类似字段 。所以我可以打电话给#34; photo-1qr333qew3qadeiof&#34;只是这样我可以在网络日志或其他东西中注意到它,但是应用程序逻辑不假设任何基于id的内容。
  • 偶尔我需要确保相关文档的唯一性,例如&#34; user&#34;文档可能完全(或至少,不超过)一个相关的&#34;个人资料&#34;文献。或者,更好的例子,也许我想确保特定交易不超过一次:避免重复购买或其他东西。所以我采取了#34; tuple&#34;可能是用户ID和内容ID,并通过doc._id标识购买记录。然后,如果特定组合意外再次发生,我将获得409 *因为确定性派生的id。
  • 甚至更少,我有时会为应用程序制作特殊ID(想想一个名为&#34; SHARED_CONFIG&#34;或者#34; MY_APP_GLOBAL_COUNTER&#34;或者......)的文档,这样它就可以直接在有限的时间内访问它们用于特定目的的案例。

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

您通常使用视图根据文档中的 来处理有意义的[二级]索引。 (是的,再次,您可以在特殊情况下使用/滥用&#34;主要&#34;索引即数据库本身'txn-'+hash(username + song._id)作为优化/技巧/黑客,但这不会是正常的练习。)

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