2016-10-23 45 views
1

我在兩個實體之間有一對多的關係:課程和文件。用MongoDB在Node.js中刪除上傳的文件

所以,我設置我的數據庫的方式是使用兩個獨立的集合:課程和文件。

var CourseSchema = new mongoose.Schema({ 
    name: { type: String, required: true }, 
    code: { type: String, required: true, unique: 1, uppercase: 1 }, 
    files: [{ type: mongoose.Schema.Types.ObjectId, ref: 'File' }] 
    // more fields 
}); 

var FileSchema = new mongoose.Schema({ 
    name: { type: String, required: true } 
    // more fields 
}); 

我有一個工作頁面,允許用戶在課程中上傳和添加文件。同樣,他們可以刪除同一頁面上的選定文件。

我擔心的是當我刪除選定的文件。選擇需要刪除的文件並單擊提交按鈕後,我發送一個DELETE請求,傳遞一個文件ID列表。下面是我刪除的文件處理程序:

var fs = require('fs'); 

var async = require('async'), 
    mongoose = require('mongoose'); 

var models = require('../models'); 

exports.deleteFiles = function (req, res) { 
    // loop through selected file-ids 
    async.eachSeries(req.body.files, function (id, done) { 
     // remove file from File collection 
     models.File.findByIdAndRemove(id, function (err, file) { 
      if (err) { 
       return done(err); 
      } else if (!file) { 
       return done(); 
      } 
      // remove file reference from Course document 
      req.course.files.pull(mongoose.Types.ObjectId(id)); 
      req.course.save(function (err) { 
       if (err) { 
        return done(err); 
       } 
       var path = __dirname + '/../public/upl/' + req.course.id + '/' + file.name; 
       // remove file from filesystem 
       fs.stat(path, function (err, stats) { 
        if (err && err.code === 'ENOENT') { 
         return done(); 
        } else if (err) { 
         return done(err); 
        } 
        if (stats.isFile()) { 
         fs.unlink(path, done); 
        } 
       }); 
      }); 
     }); 
    }, function (err) { 
     if (err) { 
      console.log(err); 
      req.flash('failure', 'Unable to delete files at this time.'); 
     } else { 
      req.flash('success', 'The files have been deleted successfully.'); 
     } 
     res.redirect('/admin/courses/' + req.course.id + '/files'); 
    }); 
}; 

這是相當混亂,因爲我必須做的幾個步驟爲每個文件ID:從課程的文件陣列刪除ID,刪除與實際收集的文件,並刪除來自文件系統的文件。另外,在每個步驟的開始處我都有一些錯誤處理代碼。

這可以通過更少的步驟和/或更好的錯誤處理來改善嗎?

回答

1

我會這樣,更清潔恕我直言寫它,使用eachwaterfall,遍歷收集和通過文件 findByIdAndRemoveFn功能

var async = require('async'); 
var File = require('../models/File'); //assume it's File.js 

exports.deleteFiles = function (req, res) { 

    var files = req.body.files; 
    var course = req.course; 
    var prePath = __dirname + '/../public/upl/' + course.id + '/'; 

    async.each(files, function(fileId, cb) { 
     async.waterfall([ 
      function findByIdAndRemoveFn(parallelCb) { 
       File.findByIdAndRemove(fileId, function(err, file) { 
        if(err) return parallelCb(err); 
        parallelCb(null, file); 
       }); 
      }, 
      function pullFn(file, parallelCb) { 
       course.update({$pull: {files: fileId}}, function(err) { 
        if(err) return parallelCb(err); 
        parallelCb(null, file); 
       }); 
      }, 
      function unlinkFn(file, parallelCb) { 
       var path = prePath + file.name; 
       fs.stat(path, function(err, stats) { 
        if(err) return parallelCb(err); 
        else if(stats.isFile()) fs.unlink(path, parallelCb); 
        else parallelCb(); 
       }); 
      } 
     ], cb); 
    }, function(err) { 
     if(err) req.flash('failure', 'Unable to delete files at this time.'); 
     else req.flash('success', 'The files have been deleted successfully.'); 
     res.redirect('/admin/courses/' + course.id + '/files'); 
    }); 
} 
+0

我喜歡這個。它更乾淨可讀。我從來不知道你可以給匿名函數命名。 – Mikey

1

另一種選擇是使用async.auto方法:

async.eachSeries(req.body.files, function (id, done) { 
    async.auto({ 
     removeFileRecord: function(cb) { 
      models.File.findByIdAndRemove(id, function (err, file) { 
       if (err) return cb(err); 
       return cb(null, file); 
      }); 
     }, 

     pullFileFromCourse: ['removeFileRecord', function(results, cb) { 
      // do nothing if file did not exist 
      if (!results.removeFileRecord) return cb(null); 

      req.course.files.pull(mongoose.Types.ObjectId(id)); 
      req.course.save(cb); 
     }], 

     unlinkFile: ['pullFileFromCourse', function(results, cb) { 
      var file = results.removeFileRecord; 

      var path = __dirname + '/../public/upl/' + req.course.id + '/' + file.name; 
      // remove file from filesystem 
      fs.stat(path, function (err, stats) { 
       if (err && err.code === 'ENOENT') { 
        return cb(); 
       } else if (err) { 
        return cb(err); 
       } 
       if (stats.isFile()) { 
        fs.unlink(path, cb); 
       } 
      }); 
     }]; 
    }, done); 
}, function (err) { 
    if (err) { 
     console.log(err); 
     req.flash('failure', 'Unable to delete files at this time.'); 
    } else { 
     req.flash('success', 'The files have been deleted successfully.'); 
    } 
    res.redirect('/admin/courses/' + req.course.id + '/files'); 
}); 
+1

修復'返回cb(文件);'在_removeFileRecord_到'返回cb(空,文件);' –