如何创建和维护 couchDB/pcouchDB doc _id
How to create and maintain couchDB/pcouchDB doc _id's
我是 couchDB 的新手,我正在努力了解 doc _id
的用法。到目前为止,我阅读和学到的是,我应该生成一个 doc _id
,这样我就可以将 B 树用于 Index/Maping。建议使用 Docuri 或 pouchdb/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
或类似字段中获取,not 从 doc._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 他们。
我是 couchDB 的新手,我正在努力了解 doc _id
的用法。到目前为止,我阅读和学到的是,我应该生成一个 doc _id
,这样我就可以将 B 树用于 Index/Maping。建议使用 Docuri 或 pouchdb/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
或类似字段中获取,not 从doc._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 他们。