2012-03-30 212 views
1

我知道这应该很容易,但我不知道如何做到这一点,尽管今天花了几个小时来看它。据我所知,似乎没有一个简单的例子或在线教程。从CouchDB创建CSV视图

我在CouchDB数据库中有几个“表”文档,每个“表”在文档中的“模式”字段中具有不同的值。所有具有相同模式的文档都包含一组相同的字段。我想要做的就是能够以CSV格式查看不同的“表格”,并且我不希望在每个模式中指定字段名称列表。

CSV输出将被R脚本使用,所以如果我可以避免它们,我不想在输出中添加任何其他标题;只是字段名称列表,用CSV格式的值逗号分隔。

例如,两个记录在 “表1” 的格式可能类似于:

{  
    "schema": "table1", 
    "field1": 17, 
    "field2": "abc", 
    ... 
    "fieldN": "abc", 
    "timestamp": "2012-03-30T18:00:00Z" 
} 

{ 
    "schema": "table1", 
    "field1": 193, 
    "field2": "xyz", 
    ... 
    "fieldN": "ijk", 
    "timestamp": "2012-03-30T19:01:00Z" 
} 

我的观点很简单:

"all": "function(doc) { 
    if (doc.schema == "table1") { 
     emit(doc.timestamp, doc) 
    } 
}" 

,因为我想按照时间戳顺序排序我的记录。

想必列表功能将是这样的:

"csv": "function(head, req) { 
    var row; 
    ... 
    // Something here to iterate through the list of fieldnames and print them 
    // comma separated 
    for (row in getRow) { 
     // Something here to iterate through each row and print the field values 
     // comma separated 
    } 
}" 

,但我不能让我的头围绕它的其余部分。

如果我想获得CSV输出看起来像

"timestamp", "field1", "field2", ..., "fieldN" 
"2012-03-30T18:00:00Z", 17, "abc", ..., "abc" 
"2012-03-30T19:01:00Z", 193, "xyz", ..., "ijk" 

应该我CouchDB的列表功能是什么样子?

在此先感谢

回答

1

这里是一些通用代码,最大奥格登写。虽然它是在节点couchapp形式,你可能得到的想法:

 
var couchapp = require('couchapp') 
    , path = require('path') 
    ; 

ddoc = { _id:'_design/csvexport' }; 

ddoc.views = { 
    headers: { 
    map: function(doc) { 
     var keys = []; 
     for (var key in doc) { 
     emit(key, 1);   
     } 
    }, 
    reduce: "_sum" 
    } 
}; 

ddoc.lists = { 
    /** 
    * Generates a CSV from all the rows in the view. 
    * 
    * Takes in a url encoded array of headers as an argument. You can 
    * generate this by querying /_list/urlencode/headers. Pass it in 
    * as the headers get parameter, e.g.: ?headers=%5B%22_id%22%2C%22_rev%5D 
    * 
    * @author Max Ogden 
    */ 
    csv: function(head, req) { 
    if ('headers' in req.query) { 
     var headers = JSON.parse(unescape(req.query.headers)); 

     var row, sep = '\n', headerSent = false, startedOutput = false; 

     start({"headers":{"Content-Type" : "text/csv; charset=utf-8"}}); 
     send('"' + headers.join('","') + '"\n'); 
     while (row = getRow()) { 
     for (var header in headers) { 
      if (row.value[headers[header]]) { 
      if (startedOutput) send(","); 
      var value = row.value[headers[header]]; 
      if (typeof(value) == "object") value = JSON.stringify(value); 
      if (typeof(value) == "string") value = value.replace(/\"/g, '""'); 
      send("\"" + value + "\""); 
      } else { 
      if (startedOutput) send(","); 
      } 
      startedOutput = true; 
     } 
     startedOutput = false; 
     send('\n'); 
     } 
    } else { 
     send("You must pass in the urlencoded headers you wish to build the CSV from. Query /_list/urlencode/headers?group=true"); 
    } 
    } 
} 

module.exports = ddoc; 

来源: https://github.com/kanso/kanso/issues/336

3

列表功能与您指定的地图作品应该是这个样子:

function(head,req) { 
    var headers; 
    start({'headers':{'Content-Type' : 'text/csv; charset=utf-8; header=present'}}); 
    while(r = getRow()) { 
    if(!headers) { 
     headers = Object.keys(r.value); 
     send('"' + headers.join('","') + '"\n'); 
    } 
    headers.forEach(function(v,i) { 
     send(String(r.value[v]).replace(/\"/g,'""').replace(/^|$/g,'"')); 
     (i + 1 < headers.length) ? send(',') : send('\n'); 
    }); 
    } 
} 

与Ryan的建议不同,要包含在列表中的字段在此函数中是不可配置的,并且必须写入任何顺序或包含字段的更改。您还必须重写所需的任何引用逻辑。