在CouchDB中执行一对多“join”的最佳方法

我正在寻找一个等同于“SQL连接”的CouchDB。

在我的例子中有CouchDB文档是列表元素:

{ "type" : "el", "id" : "1", "content" : "first" } { "type" : "el", "id" : "2", "content" : "second" } { "type" : "el", "id" : "3", "content" : "third" } 

有一个文件定义列表:

 { "type" : "list", "elements" : ["2","1"] , "id" : "abc123" } 

正如你所看到的,第三个元素被删除了,它不再是列表的一部分。 所以它不能成为结果的一部分。 现在我想要一个返回包含正确顺序的内容元素的视图。

结果可能是:

 { "content" : ["second", "first"] } 

在这种情况下,元素的顺序已经是应该的了。 另一个可能的结果

 { "content" : [{"content" : "first", "order" : 2},{"content" : "second", "order" : 1}] } 

我开始写地图function:

 map = function (doc) { if (doc.type === 'el') { emit(doc.id, {"content" : doc.content}); //emit the id and the content exit; } if (doc.type === 'list') { for ( var i=0, l=doc.elements.length; i<l; ++i ){ emit(doc.elements[i], { "order" : i }); //emit the id and the order } } } 

这是我所能得到的。 你能纠正我的错误,并写一个减lessfunction? 请记住,第三个文件不能是结果的一部分。

当然你也可以写一个不同的地图function。 但是文件的结构(一个定义要素文件和每个条目的入口文件)是不能改变的。


编辑:不要错过JasonSmith对他的回答的评论,他在这里描述如何做到这一点。

谢谢! 这是展示CouchDB 0.11新特性的一个很好的例子!

您必须使用提取相关数据function来引用视图中的文档。 或者,为了更方便的JSON,使用_list函数来清理结果。 有关详细信息,请参阅“JOIN”上的Couchio书写 。

这是计划:

  1. 首先,你对你的电子文档有唯一性限制。 如果其中两个id = 2,这是一个问题。 如果是id ,则需要使用_id字段。 CouchDB将保证唯一性,而且,这个计划的其余部分需要_id才能通过ID获取文档。

     { "type" : "el", "_id" : "1", "content" : "first" } { "type" : "el", "_id" : "2", "content" : "second" } { "type" : "el", "_id" : "3", "content" : "third" } 

    如果将文档更改为使用_id是绝对不可能的,则可以创build一个简单视图来emit(doc.id, doc) ,然后将其重新插入到临时数据库中。 这将id转换为_id但增加了一些复杂性。

  2. 该视图发出键入[list_id, sort_number]上的{"_id": content_id}数据,以将它们的内容“聚集”到列表中。

     function(doc) { if(doc.type == 'list') { for (var i in doc.elements) { // Link to the el document's id. var id = doc.elements[i]; emit([doc.id, i], {'_id': id}); } } } 

    现在有一个简单的el文档列表,按照正确的顺序。 如果你只想看到一个特定的列表,你可以使用startkeyendkey

     curl localhost:5984/x/_design/myapp/_view/els {"total_rows":2,"offset":0,"rows":[ {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","0"],"value":{"_id":"2"}}, {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","1"],"value":{"_id":"1"}} ]} 
  3. 要获取el内容,请使用include_docs=true查询。 通过_id的魔法, el文件将会加载。

     curl localhost:5984/x/_design/myapp/_view/els?include_docs=true {"total_rows":2,"offset":0,"rows":[ {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","0"],"value":{"_id":"2"},"doc":{"_id":"2","_rev":"1-4530dc6946d78f1e97f56568de5a85d9","type":"el","content":"second"}}, {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","1"],"value":{"_id":"1"},"doc":{"_id":"1","_rev":"1-852badd683f22ad4705ed9fcdea5b814","type":"el","content":"first"}} ]} 

    注意,这已经是你所需要的所有信息。 如果你的客户端是灵活的,你可以parsing这个JSON的信息。 下一个可选步骤简单地重新格式化,以匹配您所需要的。

  4. 使用一个_list函数,它简单地重新格式化视图输出。 人们使用它们输出XML或HTML,但是我们将使JSON更加方便。

     function(head, req) { var headers = {'Content-Type': 'application/json'}; var result; if(req.query.include_docs != 'true') { start({'code': 400, headers: headers}); result = {'error': 'I require include_docs=true'}; } else { start({'headers': headers}); result = {'content': []}; while(row = getRow()) { result.content.push(row.doc.content); } } send(JSON.stringify(result)); } 

    结果匹配。 当然在生产中你需要startkeyendkey来指定你想要的列表。

     curl -g 'localhost:5984/x/_design/myapp/_list/pretty/els?include_docs=true&startkey=["abc123",""]&endkey=["abc123",{}]' {"content":["second","first"]}