2

最近,我在业余时间一直在使用 Couch DB 进行大量工作,并且非常喜欢使用它。我发现它比使用关系数据库灵活得多,但也不是没有缺点。

一个很大的缺点是缺乏动态查询/视图生成......因此,您必须做大量工作来规划和证明您的视图,因为您不能像使用 SQL 那样将逻辑放入应用程序代码中.

例如,我基于一个 JSON 文档模板编写了一个登录方案,看起来有点像这样:

{ 
   "_id": "blah",
   "type": "user",
   "name": "Bob",
   "email": "bob@theaquarium.com",
   "password": "blah",
}

为了防止创建重复帐户,我编写了一个非常基本的视图来生成用户名列表以作为键查找:

emit(doc.name, null) 

这对我来说似乎相当有效。我认为这比拖出整个文档列表(甚至只是减少每个文档的字段数量)要好得多。所以我做了完全相同的事情来生成一个电子邮件地址列表:

emit(doc.email, null)

你能看出我要问这个问题吗?

在关系数据库(使用 SQL)中,只需对同一张表进行两次查询。这种技术(将视图等同于 SQL 查询的结果)会在某种程度上类似吗?

然后是性能/效率问题......这两个视图真的应该只是一个吗?还是使用带有键且没有关联值的 Couch DB 视图是一种有效的做法?考虑到上面的示例,这两个视图都将在登录方案之外使用......如果我需要生成用户名列表,我可以在没有额外开销的情况下检索它们。

你怎么看?

4

1 回答 1

1

首先,您当然可以将视图逻辑放入您的应用程序代码中——您所需要的只是一个适当的构建或部署系统,该系统从应用程序中提取视图并将它们添加到设计文档中。缺少的是动态生成新查询的能力。

你的emit(doc.field,null)方法当然并不令人惊讶或不寻常。事实上,这是“按字段查找文档”查询的常用模式,其中使用include_docs=true. 也没有必要将两个视图混合为一个,唯一与性能相关的决定是两个视图是否应该放在同一个设计文档中:设计文档中的所有视图在访问它们时都会更新。

当然,您的方法实际上并不能保证电子邮件是唯一的,即使您的应用程序非常努力。想象以下具有两个客户端应用程序 A 和 B 的情况:

A: queries view, determines that `test@email.com` does not exist.
B: queries view, determines that `test@email.com` does not exist.
A: creates account with `test@email.com`
B: creates account with `test@email.com`

这是一种罕见的情况,但仍有可能。更好的方法是保留使用电子邮件地址作为密钥的文档,因为对单个文档的访问是事务性的(不可能使用相同的密钥创建两个文档)。典型例子:

{
  _id: "test@email.com",
  type: "email"
  user: "000000001"
}

{
  _id: "000000001",
  type: "user", 
  email: "test@email.com",
  firstname: "Test", 
  ...
}

编辑:仅当尝试为给定电子邮件创建帐户的两个客户端将可靠地尝试访问同一文档时,保留模式才有效。如果您随机生成一个新标识符,那么客户端 A 将创建并保留文档 XXXX,而客户端 B 将创建并保留文档 YYYY,您最终将得到两个具有相同电子邮件的不同文档。

同样,执行事务性“检查是否存在,如果不存在则创建”操作的唯一方法是让所有客户端更改单个文档。

于 2012-01-30T12:18:47.673 回答