CouchDB:单个文档与“加入”文档文件在一起 [英] CouchDB: Single document vs "joining" documents together

查看:85
本文介绍了CouchDB:单个文档与“加入”文档文件在一起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



有两种存储方式。可以在包含适当JSON数据表示形式的单个文档中,也可以将条目的每个部分存储在单独的文档中,稍后再通过视图将它们组合在一起(类似于:



创建这样的视图

  fullQuestion:{
map:function(doc){
if(doc.type =='question')发出([doc._id,null,null],null);
if(doc.type =='answer')发出([doc.question,doc._id,null],null);
if(doc.type =='comment')发出([doc.question,doc.answer,doc._id],null);
}
}

并查询这样的视图

  http:// localhost:5984 / so / _design / app / _view / fullQuestion?startkey = ['12345']& endkey = [' 12345',{},{}]& include_docs = true 

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



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



编辑:这是视图和查询的替代选项



根据您的域,您知道一些事实。您知道在问题存在之前就不可能存在答案,在答案存在之前就不能存在对答案的评论。因此,让我们创建一个视图,使其可以更快地创建显示页面,并遵循事物的顺序:

  fullQuestion:{
map:function(doc){
if(doc.type =='question')发出([doc._id,doc.date],null);
if(doc.type ==‘answer’)发出([doc.question,doc.date],null);
if(doc.type =='comment')发出([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));
}

函数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)
})

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



希望这会有所帮助。


I'm tryting to decide the best approach for a CouchApp (no middleware). Since there are similarities to my idea, lets assume we have a stackoverflow page stored in a CouchDB. In essence it consists of the actual question on top, answers and commets. Those are basically three layers.

There are two ways of storing it. Either within a single document containing a suitable JSON representation of the data, or store each part of the entry within a separate document combining them later through a view (similar to this: http://www.cmlenz.net/archives/2007/10/couchdb-joins)

Now, both approaches may be fine, yet both have massive downsides from my current point of view. Storing a busy document (many changes through multiple users are expected) as a signle entity would cause conflicts to happen. If user A stores his/her changes to the document, user B would receive a conflict error once he/she is finished typing his/her update. I can imagine its possible to fix this without the users knowledge through re-downloading the document before retrying.

But what if the document is rather big? I'll except them to become rather blown up over time which would put quite some noticeable delay on a save process, especially if the retry process has to happen multiple times due to many users updating a document at the same time.

Another problem I'd see is editing. Every user should be allowed to edit his/her contributions. Now, if they're stored within one document it might be hard to write a solid auth handler.

Ok, now lets look at the multiple documents approach. Question, Answers and Comments would be stored within their own documents. Advantage: only the actual owner of the document can cause conflicts, something that won't happen too often. Being rather small elements of the whole, redownloading wouldn't take much time. Furthermore the auth routine should be quite easy to realize.

Now here's the downside. The single document is real easy to query and display. Having a lot of unsorted snippets laying around seems like a messy thing since I didn't really get the actual view to present me with a 100% ready to use JSON object containing the entire item in an ordered and structured format.

I hope I've been able to communicate the actual problem. I try to decide which solution would be more suitable for me, which problems easier to overcome. I imagine the first solution to be the prettier one in terms of storage and querying, yet the second one the more practical one solvable through better key management within the view (I'm not entirely into the principle of keys yet).

Thank you very much for your help in advance :)

解决方案

Go with your second option. It's much easier than having to deal with the conflicts. Here are some example docs how I might structure the data:

{
   _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
}

To store revisions of each one, I would store the old versions as attachments on the doc being edited. If you use the jquery client for couchdb, you get it for free by adding the jquery.couch.attachPrevRev = true. See Versioning docs in CouchDB by jchris

Create a view like this

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) ;
   }
}

And query the view like this

http://localhost:5984/so/_design/app/_view/fullQuestion?startkey=['12345']&endkey=['12345',{},{}]&include_docs=true

(Note: I have not url encoded this query, but it is more readable)

This will get you all of the related documents for the question that you will need to build the page. The only thing is that they will not be sorted by date. You can sort them on the client side (in javascript).

EDIT: Here is an alternative option for the view and query

Based on your domain, you know some facts. You know an answer cant exist before a question existed, and a comment on an answer cant exist before an answer existed. So lets make a view that might make it faster to create the display page, respecting the order of things:

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);
   }
 }

This will keep all the related docs together, and keep them ordered by date. Here is a sample query

http://localhost:5984/so/_design/app/_view/fullQuestion?startkey=['12345']&endkey=['12345',{}]&include_docs=true

This will get back all the docs you will need, ordered from oldest to newest. You can now zip through the results, knowing that the parent objects will be before the child ones, like this:

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)
})

So then you dont have to perform any client side sorting.

Hope this helps.

这篇关于CouchDB:单个文档与“加入”文档文件在一起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆