【问题标题】:Deleting uploaded files in Node.js with MongoDB使用 MongoDB 在 Node.js 中删除上传的文件
【发布时间】:2016-10-23 05:41:04
【问题描述】:

我在两个实体之间存在一对多关系:课程和文件。

因此,我设置数据库的方式是使用两个单独的集合:课程和文件。

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,从实际集合中删除文件,然后从文件系统中删除文件。同样,我在每个步骤的开头都有一些错误处理代码。

是否可以使用更少的步骤和/或更好的错误处理来改进这一点?

【问题讨论】:

    标签: node.js error-handling mongoose delete-file


    【解决方案1】:

    我会这样写,更简洁,恕我直言,使用 eachwaterfall 来遍历集合并从 findByIdAndRemoveFn 函数传递 file

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

    【讨论】:

    • 我喜欢这个。它更清洁和可读。而且我从来不知道你可以给匿名函数命名。
    【解决方案2】:

    另一种选择是使用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');
    });
    

    【讨论】:

    • removeFileRecord 上的 return cb(file); 修复为 return cb(null, file);
    猜你喜欢
    • 1970-01-01
    • 2020-05-02
    • 2014-01-14
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    相关资源
    最近更新 更多