0

I am trying to insert multiple images to couchdb via nano using express 4 and formidable. I can access and insert individual files without difficulty using formidable and nano, however, when I try to insert one file after another, I get conflict errors. I am very new to js and node, and I know my understanding of callbacks and asynchronous functions is limited. This is what I have at the moment. Any help would be greatly appreciated.

function uploadImage(req, res) {

var form = new formidable.IncomingForm(),
files = [],
fields = [];
uploadcount = 1;

form.on('field', function(field, value) {
  fields.push([field, value]);
})

form.on('file', function(field, file) {
  files.push([field, file]);
  var docid = fields[0][1];
  getrevision();

  function getRevision(){
    dbn.get(docid, { revs_info: true }, function(err,body, file){
      if (!err) {
        exrev = body._rev;
        insertImage(exrev);
      }else{ 
        console.log(err);
      }
    });  
  }

  function insertImage(exrevision){
    var exrev = exrevision;
    fs.readFile(file.path, function (err, data) {
      if (err){
        console.log(err);}else{              
          var imagename = docid + "_" + uploadcount + ".png";
          dbn.attachment.insert(docid,imagename,data,'image/png',
          { rev: exrev }, function(err,body){
            if (!err) {
              uploadcount++;
            }else{ 
              console.log(err);
            }
          });
        };        
    });
  };
});

form.on('end', function() {
  console.log('done');
  res.redirect('/public/customise.html');
});

form.parse(req);

};

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189

2 Answers2

0

I found a solution by dumping the files first into a temporary directory, then proceeding to insert the files into couchdb via nano all within a single function. I couldn't find a way to pause the filestream to wait for the couchdb response, so this sequential method seems adequate.

0

This is a problem handling asynchronous calls. Because each attachment insert requires the doc's current rev number, you can't do the inserts in parallel. You must insert a new attachment only after you get a response from the the previous one.

You may use the promise and deferred mechanism to do this. But, I personally have solved a similar problem using a package called "async". In async, you can use async.eachSeries() to make these async calls in series.

Another point is about the revision number, you may just use the lighter weight db.head() function, instead of db.get(). The rev number is presented under the "etag" header. You can get the rev like this:

// get Rev number
db.head(bookId, function(err, _, headers) {
    if (!err) {
        var rev = eval(headers.etag);

        // do whatever you need to do with the rev number
        ......
    }
});

In addition, after each attachment insert, the response from couchdb will look something like this:

{"ok":true,"id":"b2aba1ed809a4395d850e65c3ff2130c","rev":"4-59d043853f084c18530c2a94b9a2caed"} 

The rev property will give the new rev number which you may use for inserting to the next attachment.

Joe H
  • 1,447
  • 2
  • 11
  • 8