从CouchDB创建CSV视图

时间:2012-03-30 11:59:17

标签: csv couchdb

我知道这应该很简单,但我无法解决如何做到这一点尽管今天花了几个小时看它。据我所知,似乎没有一个简单的在线示例或教程。

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

CSV输出将被R脚本消耗,所以如果我能避免它,我不希望输出中有任何额外的标题;只是字段名列表,逗号分隔,CSV格式的值。

例如,“table1”格式的两条记录可能如下所示:

{    
   "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列表功能应该是什么样的?

提前致谢

2 个答案:

答案 0 :(得分: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的建议不同,列表中包含的字段在此函数中是不可配置的,并且必须写入顺序或包含字段的任何更改。您还必须重写所需的任何引用逻辑。

答案 1 :(得分:1)

这是Max Ogden撰写的一些通用代码。虽然它是以node-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