我对索引我的视图的最好方法有些疑问。
假设我存储了链接"用户"到"组"的文档,如下所示:
{
"groupId": "<group_id>",
"userId": "<user_id>"
}
我想检索链接到一个用户的所有组,所以显然映射它的最好方法是:
emit(doc.userId, doc.groupId);
,我可以通过使用key=<user_id>
查询视图来检索组。
但是现在,如果我想删除与特定用户/组对对应的文档,我需要遍历视图查询的所有结果,直到找到正确的值并获得文档的ID。
所以我认为一个更好的索引视图的方法是:
emit([doc.userId, doc.groupId], null);
现在我可以通过发出范围查询和解析返回行的键来获得链接到用户的所有组,并且还可以使用"full"键直接命中特定文档(如果存在)。但是我担心范围查询(它将比"完整"查询更频繁地被调用)的性能会比最初的方法更差。
如果有任何见解,我将不胜感激,谢谢!
我相信您应该抵制创建太多小文档的冲动(这是我们从SQL数据库经验中带来的)。在这个用例中(当然是示例),单个组的用户列表或单个用户的组列表都可以是单个文档。
显然,一个组的用户很可能有多个并发编辑,从而导致冲突,但一个用户对组列表进行多个并发编辑的可能性较小。
因此,我建议为每个用户创建一个单独的文档,列出他们的组(或者只是将其作为一个数组添加到其他以用户为中心的文档中)。使用基于用户ID的固定文档ID方案,这样您就可以直接通过ID访问文档,而无需在视图中查找文档。现在您只需要发出一个特定组的用户视图。
如果一个用户离开了一个组,你只需要更新他们的组偏好。如果删除了一个组,那么您就需要从每个组成员的首选项中查找和删除组ID,但这将是一个不太常见的任务,并且通常只由更能容忍长时间运行流程的管理员执行。
当然,最终的答案是衡量任何对你来说重要的指标。
然而,我认为性能将大致相同。在每种情况下,您将为每个{user, group}对发出一个视图行。
视图可以有多个具有相同"键"的行。因此,当您查询key=<user_id>
时,您仍然在执行范围查询("CouchDB,显示我所有以user_id开始并以user_id结束的视图行。"),所以我认为您会看到类似的性能。
对我来说,最大的性能问题似乎是延迟:多次往返查询这个视图,然后继续查询文档。当然,您可以添加?include_docs=true
,但这仍然会增加额外的i/o负载。(在我看来,额外的成本主要是理论上的,在实际应用中并没有那么糟糕。)
要删除文档,需要的不仅仅是id。你也需要复习。因此,为了略微提高性能并减少往返和延迟,您可以释放一个更有用的值,而不是null
。例如,发出整个文档!或者释放出{"_id":doc._id, "_rev":doc._rev}
。这样,您就可以通过向/db/<id>?rev=<rev>
发出delete命令来删除文档。