Создание CSV-представления из CouchDB - PullRequest
2 голосов
/ 30 марта 2012

Я знаю, что это должно быть легко, но я просто не могу понять, как это сделать, несмотря на то, что провел несколько часов, глядя на это сегодня. Насколько я могу судить, в Интернете нет простого примера или учебника.

У меня есть несколько «таблиц» документов в базе данных 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 ]

3 голосов
/ 02 апреля 2012

Функция списка, которая работает с данной картой, должна выглядеть примерно так:

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

В отличие от предложения Райана, поля для включения в список не настраиваются в этой функции, и любые изменения в порядкеили включенные поля должны быть записаны. Вы также должны были бы переписать любую необходимую логику цитирования.

1 голос
/ 30 марта 2012

Вот некоторый общий код, который написал Макс Огден. Пока он находится в форме 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...