2

好的 SO 用户。我正在尝试学习和使用 CouchDB。我将 StackExchange 数据导出加载为 XML 文件中的每行文档,因此沙发上的文档基本上如下所示:

//This is a representation of a question:
{
 "Id" : "1",
 "PostTypeId" : "1",
 "Body" : "..."
}

//This is a representation of an answer
{
 "Id" : "1234",
 "ParentId" : "1",
 "PostTypeId" : "2"
 "Body" : "..."
}

(请忽略这些文件的导入基本上将所有属性都视为文本,我理解使用实数,布尔值等可以产生更好的空间/处理效率。)

我想做的是将其映射到单个聚合文档中:

这是我的地图:

function(doc) {
    if(doc.PostTypeId === "2"){
      emit(doc.ParentId, doc);
    }
    else{
        emit(doc.Id, doc);
    }
}

这是减少:

function(keys, values, rereduce){
    var retval = {question: null, answers : []};

    if(rereduce){
        for(var i in values){
            var current = values[i];
            retval.answers = retval.answers.concat(current.answers);
            if(retval.question === null && current.question !== null){
                retval.question = current.question;
            }
        }
    }
    else{
        for(var i in values){
            var current = values[i];            

            if(current.PostTypeId === "2"){
                retval.push(current);
            }
            else{
                retval.question = current;
            }
        }
    }
    return retval;
}

从理论上讲,这将产生如下文件:

{
    "question" : {...},
    "answers" : [answer1, answer2, answer3]
}

但相反,我得到了标准的“没有足够快地减少”错误。

我是否错误地使用了 Map-Reduce,是否有一个完善的模式可以在 CouchDb 中实现这一点?

(另请注意,我希望得到完整文档的回复,其中问题是“父母”,答案是“孩子”,而不仅仅是 ID。)

4

1 回答 1

3

所以,完成我上面要做的事情的“正确”方法是添加一个“列表”作为我的设计文档的一部分。(我试图达到的目的似乎被称为“整理文件”)。

无论如何,您可以随心所欲地配置您的地图,并将其与同一功能中的“列表”结合起来。

为了解决上面的问题,我去掉了我的reduce(只有一个map函数),然后添加了一个类似下面的函数:

{
   "_id": "_design/posts",
   "_rev": "11-8103b7f3bd2552a19704710058113b32",
   "language": "javascript",
   "views": {
       "by_question_id": {
           "map": "function(doc) {
                if(doc.PostTypeId === \"2\"){
                    emit(doc.ParentId, doc);
                }
                else{
                    emit(doc.Id, doc);
                }
            }"
       }
   },
   "lists": {
       "aggregated": "function(head, req){ 
                        start({\"headers\": {\"Content-Type\": \"text/json\"}});
                        var currentRow = null;
                        var currentObj = null; 
                        var retval = []; 
                        while(currentRow = getRow()){
                            if(currentObj === null || currentRow.key !== currentObj.key){
                                currentObj = {key: currentRow.key, question : null, answers : []};
                                retval.push(currentObj);
                            } 
                            if(currentRow.value.PostTypeId === \"2\"){
                                currentObj.answers.push(currentRow.value);
                            } 
                            else{
                                currentObj.question = currentRow.value;
                            }
                        }
                        send(toJSON(retval));
                    }"
   }
}

所以,在你加载了一些元素之后,你可以像这样访问它们:

http://localhost:5984/<db>/_design/posts/_list/aggregated/by_question_id?<standard view limiters>

我希望这可以节省人们一些时间。

于 2012-11-25T23:32:37.850 回答