How do you upload an image file to mongoose database using mean js

15,227

Solution 1

You have plenty ways and tools to achieve what you want. I put one of them here:

For this one I use angular-file-upload as client side. So you need this one in your controller:

        $scope.onFileSelect = function(image) {
            if (angular.isArray(image)) {
                image = image[0];
            }

            // This is how I handle file types in client side
            if (image.type !== 'image/png' && image.type !== 'image/jpeg') {
                alert('Only PNG and JPEG are accepted.');
                return;
            }

            $scope.uploadInProgress = true;
            $scope.uploadProgress = 0;

            $scope.upload = $upload.upload({
                url: '/upload/image',
                method: 'POST',
                file: image
            }).progress(function(event) {
                $scope.uploadProgress = Math.floor(event.loaded / event.total);
                $scope.$apply();
            }).success(function(data, status, headers, config) {
                $scope.uploadInProgress = false;
                // If you need uploaded file immediately 
                $scope.uploadedImage = JSON.parse(data);      
            }).error(function(err) {
                $scope.uploadInProgress = false;
                console.log('Error uploading file: ' + err.message || err);
            });
        };

And following code in your view (I also added file type handler for modern browsers):

Upload image <input type="file" data-ng-file-select="onFileSelect($files)" accept="image/png, image/jpeg">
<span data-ng-if="uploadInProgress">Upload progress: {{ uploadProgress }}</span>
<img data-ng-src="uploadedImage" data-ng-if="uploadedImage">

For server side, I used node-multiparty.

And this is what you need in your server side route:

app.route('/upload/image')
    .post(upload.postImage);

And in server side controller:

var uuid = require('node-uuid'),
    multiparty = require('multiparty'),
    fs = require('fs');

exports.postImage = function(req, res) {
    var form = new multiparty.Form();
    form.parse(req, function(err, fields, files) {
        var file = files.file[0];
        var contentType = file.headers['content-type'];
        var tmpPath = file.path;
        var extIndex = tmpPath.lastIndexOf('.');
        var extension = (extIndex < 0) ? '' : tmpPath.substr(extIndex);
        // uuid is for generating unique filenames. 
        var fileName = uuid.v4() + extension;
        var destPath = 'path/to/where/you/want/to/store/your/files/' + fileName;

        // Server side file type checker.
        if (contentType !== 'image/png' && contentType !== 'image/jpeg') {
            fs.unlink(tmpPath);
            return res.status(400).send('Unsupported file type.');
        }

        fs.rename(tmpPath, destPath, function(err) {
            if (err) {
                return res.status(400).send('Image is not saved:');
            }
            return res.json(destPath);
        });
    });
};

As you can see, I store uploaded files in file system, so I just used node-uuid to give them unique name. If you want to store your files directly in database, you don't need uuid, and in that case, just use Buffer data type. Also please take care of things like adding angularFileUpload to your angular module dependencies.

Solution 2

I got ENOENT and EXDEV errors. After solving these, below code worked for me.

var uuid = require('node-uuid'),
multiparty = require('multiparty'),
fs = require('fs');

var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
    var file = files.file[0];
    var contentType = file.headers['content-type'];
    var tmpPath = file.path;
    var extIndex = tmpPath.lastIndexOf('.');
    var extension = (extIndex < 0) ? '' : tmpPath.substr(extIndex);
    // uuid is for generating unique filenames.
    var fileName = uuid.v4() + extension;
    var destPath = appRoot +'/../public/images/profile_images/' + fileName;

    // Server side file type checker.
    if (contentType !== 'image/png' && contentType !== 'image/jpeg') {
        fs.unlink(tmpPath);
        return res.status(400).send('Unsupported file type.');
    }

    var is = fs.createReadStream(tmpPath);
    var os = fs.createWriteStream(destPath);

    if(is.pipe(os)) {
        fs.unlink(tmpPath, function (err) { //To unlink the file from temp path after copy
            if (err) {
                console.log(err);
            }
        });
        return res.json(destPath);
    }else
        return res.json('File not uploaded');
});

for variable 'appRoot' do below in express.js

path = require('path');
global.appRoot = path.resolve(__dirname);
Share:
15,227
user3775998
Author by

user3775998

Updated on July 21, 2022

Comments

  • user3775998
    user3775998 almost 2 years

    I am new to the mean stack. I want to know how to upload an image file to the database(mongoose) through angularjs. If possible, please provide me with some code. I have searched the internet but I haven't found any suitable code.

  • Ivan Prihhodko
    Ivan Prihhodko over 9 years
    I believe the require should actually be var uuid = require('node-uuid')
  • Brian
    Brian over 9 years
    @Foad - thanks for this, really great. For me, this creates a file at os.tmpDir() which is then outside of the server root, so the call to fs.rename() fails because it's outside of read/write permissions. Any ideas?
  • Dave
    Dave over 9 years
    @Brian You can always use __dirname to retrieve the executing directory and choose a relative path in your app's file structure.
  • Charlie Tupman
    Charlie Tupman almost 9 years
    @Foad Nosrati Habibi thank you for this solution, I am just geting used to the Mean Stack and don't know where I would be without these examples. I am looking to enhance this solution to include uploads of multiple images, if you have any information on how to do this I would really appreciate it.
  • nabinca
    nabinca over 8 years
    This works like a charm! :) ([email protected], [email protected], [email protected])
  • olyjosh
    olyjosh almost 8 years
    I think its neccessary you include a way of creating such directory if not existing. I first get this ENOENT error before making modifications as follow var destPath = appRoot + '/public/images/profile_images/'; if (!fs.existsSync(destPath)) { fs.mkdirSync(destPath); } var destPath = destPath+fileName;
  • olyjosh
    olyjosh almost 8 years
    In your angular, these $scope.upload = $upload.upload({ ::::::::::::::::::: to ::::::::::::::::::::: $scope.upload = Upload.upload({ The $upload doesn't work for me but Upload as document on github.com/danialfarid/ng-file-upload#node