如何最好地解决CouchDB的非RDBMS限制

时间:2013-03-15 19:08:58

标签: nosql couchdb relational-database

我们有两种文档“类型”:PostUser

典型帖子:

{
   "_id": "3847345345",
   "Schema": "Post",
   "Text": "Hello World! This is a post!",
   "IsFeatured": true,
   "UserID": "12345345345234234"
}

典型用户:

{
   "_id": "12345345345234234",
   "Schema": "User",
   "Username": "georgepowell"
   "PostIds": ["3847345345","5135345345","9987453236", ... ]
}

在显示Post的网页上,该帖子旁边会显示该帖子的Username(加上有关该用户的其他任何可更改信息)。与SO类似: user info

这是SQL JOIN完美的典型示例,但当然CouchDB不支持这样的事情。相反,我们可以制作一个视图,为User Post上的Post文档和_id文档编制索引。像这样:

function(doc) {
    if (doc.Schema = 'Post') {
        emit([doc._id, 0], null);
    } else if (doc.Schema = 'User') {
        foreach (string id in doc.PostIds) // not javascript I know. shhh
            emit([id, 1], null);
    }
}

效果很好,因为我们可以有效地检索我们需要的所有信息,只需Post _id {。}}。

但是,如果我想创建一个列出IsFeatured == true所有帖子以及所有用户数据的视图,我就会卡住!

function(doc) {
    if (doc.Schema = 'Post' && doc.IsFeatured) {
        emit([doc._id, 0], null);
    } else if (doc.Schema = 'User') {
        foreach (string id in doc.PostIds)
            emit([id, 1], null); // I can't check if the post is featured!
    }
}

我是否达到了关系数据的CouchDB限制?或者这种索引在CouchDB中是否可行?

1 个答案:

答案 0 :(得分:2)

由于它是一种不同的技术,因此需要权衡利弊。有时虽然看起来它们会在短期内占用更多资源(额外的请求)但它可能是无关紧要的,并且从长远来看可能会提供显着的可扩展性,如果你需要这样的东西。

CouchDB可以同时处理许多不同的“数据库”,您可以将其视为不同的模型空间。因此,使用相同的CouchDB运行实例,您可以拥有/users/posts。这在CouchDB的配置或性能方面绝对不需要额外的工作。

这可以使您的地图代码更加直接,因为您不需要拥有“架构”字段并将其合并到每个地图功能中。

此外,您可以(并且应该)在给定的设计视图中具有多个不同的map / reduce对。这很重要,因为如果您有两个不同的文档“Schema”emit(doc.id, doc.val),您怎么知道哪个用于减少目的。

查看数据的更多CouchDB惯用方法是不将post_ids保存在用户身上。只是帖子上的UserID,然后有一个类似于以下帖子的地图:

(doc) ->
  emit([doc.user_id, doc.isFeatured], null);
  emit([doc.isFeatured, doc.createdAt], doc.user_id);

然后,使用?start_key=['12345345345234234']&end_key=['12345345345234234',{}]之类的参数向视图API发出请求将获得所有帖子。

凡有?key=['12345345345234234', 1]的人才能获得精选帖子。

第二个发射还使您能够快速获取按日期排序的整个系统中的所有帖子 - 如果您想要这些数据,则由谁制作,而不会将所有帖子发送到管道