CouchDB:单个文档与 "joining"个文档放在一起

标签 couchdb couchapp

我正在尝试确定 CouchApp(无中间件)的最佳方法。由于与我的想法有相似之处,让我们假设我们有一个存储在 CouchDB 中的 stackoverflow 页面。本质上,它由顶部的实际问题、答案和commets 组成。这些基本上是三层。

有两种存储方式。要么在包含数据的合适 JSON 表示的单个文档中,要么将条目的每个部分存储在单独的文档中,稍后通过 View 将它们组合起来(类似于: http://www.cmlenz.net/archives/2007/10/couchdb-joins )

现在,这两种方法可能都不错,但从我目前的观点来看,两者都有很大的缺点。将繁忙的文档(预计会通过多个用户进行许多更改)作为信号实体存储会导致发生冲突。如果用户 A 存储他/她对文档的更改,则用户 B 将在他/她完成输入他/​​她的更新后收到冲突错误。我可以想象在用户不知情的情况下通过在重试之前重新下载文档来解决这个问题是可能的。

Multi User Update problem

但是如果文档比较大怎么办?我会排除它们随着时间的推移变得相当爆炸,这会在保存过程中产生相当明显的延迟,特别是如果由于许多用户同时更新文档而必须多次发生重试过程。

我看到的另一个问题是编辑。每个用户都应该被允许编辑他/她的贡献。现在,如果它们存储在一个文档中,则可能很难编写可靠的身份验证处理程序。

好的,现在让我们看看多文档方法。问题、答案和评论将存储在他们自己的文档中。优点:只有文档的实际所有者才能引起冲突,这种情况不会经常发生。作为整体中相当小的元素,重新下载不会花费太多时间。此外,身份验证例程应该很容易实现。

现在是缺点。单个文档非常易于查询和显示。放置大量未排序的片段似乎是一件困惑的事情,因为我并没有真正获得实际 View 来向我展示一个 100% 准备使用的 JSON 对象,其中包含有序和结构化格式的整个项目。

enter image description here

我希望我已经能够传达实际问题。我尝试决定哪种解决方案更适合我,哪些问题更容易克服。我想象第一个解决方案在存储和查询方面更漂亮,而第二个解决方案更实用,可以通过 View 中更好的 key 管理来解决(我还没有完全了解 key 的原理)。

非常感谢您提前提供帮助:)

最佳答案

选择第二个选项。这比处理冲突要容易得多。以下是我如何构造数据的一些示例文档:

{
   _id: 12345,
   type: 'question',
   slug: 'couchdb-single-document-vs-joining-documents-together',
   markdown: 'Im tryting to decide the best approach for a CouchApp (no middleware). Since there are similarities to...' ,
   user: 'roman-geber',
   date: 1322150148041,
   'jquery.couch.attachPrevRev' : true
}
{
   _id: 23456,
   type: 'answer'
   question: 12345,
   markdown: 'Go with your second option...',
   user : 'ryan-ramage',
   votes: 100,
   date: 1322151148041,
   'jquery.couch.attachPrevRev' : true
}
{
   _id: 45678,
   type: 'comment'
   question: 12345,
   answer: 23456,
   markdown : 'I really like what you have said, but...' ,
   user: 'somedude',
   date: 1322151158041, 
   'jquery.couch.attachPrevRev' : true
}

为了存储每个版本的修订,我会将旧版本存储为正在编辑的文档的附件。如果您将 jquery 客户端用于 couchdb,您可以通过添加 jquery.couch.attachPrevRev = true 来免费获得它。见 Versioning docs in CouchDB by jchris

创建这样的 View
fullQuestion : {
   map : function(doc) {
       if (doc.type == 'question') emit([doc._id, null, null], null);
       if (doc.type == 'answer')   emit([doc.question, doc._id, null], null);
       if (doc.type == 'comment')  emit([doc.question, doc.answer, doc._id], null) ;
   }
}

并像这样查询 View
http://localhost:5984/so/_design/app/_view/fullQuestion?startkey=['12345']&endkey=['12345',{},{}]&include_docs=true

(注意:我没有对这个查询进行 url 编码,但它更具可读性)

这将为您提供构建页面所需的问题的所有相关文档。唯一的问题是它们不会按日期排序。您可以在客户端(在 javascript 中)对它们进行排序。

EDIT :这是 View 和查询的替代选项

根据您的域,您知道一些事实。您知道在问题存在之前不能存在答案,并且在答案存在之前不能存在对答案的评论。因此,让我们创建一个 View ,可以更快地创建显示页面,尊重事物的顺序:
fullQuestion : {
   map : function(doc) {
       if (doc.type == 'question') emit([doc._id, doc.date], null);
       if (doc.type == 'answer')   emit([doc.question, doc.date], null);
       if (doc.type == 'comment')  emit([doc.question, doc.date], null);
   }
 }

这会将所有相关文档保存在一起,并按日期对它们进行排序。这是一个示例查询
http://localhost:5984/so/_design/app/_view/fullQuestion?startkey=['12345']&endkey=['12345',{}]&include_docs=true

这将取回您需要的所有文档,按从旧到新的顺序排列。您现在可以压缩结果,知道父对象将在子对象之前,如下所示:
function addAnswer(doc) {
   $('.answers').append(answerTemplate(doc));
}

function addCommentToAnswer(doc) {
   $('#' + doc.answer).append(commentTemplate(doc));
}

$.each(results.rows, function(i, row) {
   if (row.doc.type == 'question') displyQuestionInfo(row.doc);
   if (row.doc.type == 'answer') addAnswer(row.doc);
   if (row.doc.type == 'comment') addCommentToAnswer(row.doc)
})

因此,您不必执行任何客户端排序。

希望这可以帮助。

关于CouchDB:单个文档与 "joining"个文档放在一起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8255670/

相关文章:

node.js - 从 NodeJS 的 Cloudant/CouchDB 数据库中获取最新文档

couchdb - 在 CouchDB 中使用 require() 或//!json、!code?

javascript - Couchdb:是否可以从另一个 View 中查询一个 View ?

javascript - Pouchdb 如何将附件放入 for 循环中?

node.js - 使用 nano 从 View 中读取数据

mongodb - CouchDB 或 MongoDB 中的哪一个适合我的需求?

couchdb - Couchapp目录结构,是否更新?

couchdb - 没有服务器端的CouchApp或具有xdomain问题的CouchDB后端?

grails - 哪个框架用于访问 couchDB 的门户网站?

couchdb - 从 couchdb View 访问 session 信息