如何将nodejs中的多个文件上传到AWS S3并将文件url保存到数据库中?

阿斯兰·阿米尔

嗨,我需要在 s3 上一次上传多张图片。目前我正在使用express-fileupload在 AWS 上上传单个图像,并且我想使用相同的方法将多个文件上传到 s3 并使用 mongodb 上的 url 更新图像数组。

我的架构属性:

const ServiceSchema = new mongoose.Schema(
{
    photo: [
        {
            type: String,
            default: 'no-photo.jpg',
        },
    ],
});
module.exports = mongoose.model('Service', ServiceSchema);

我的控制器:

// @desc        Upload photo for service
// @route       PUT /api/v1/services/:id/photo
// @access      Private
exports.servicePhotoUpload = asyncHandler(async (req, res, next) => {
const service = await Service.findById(req.params.id);

if (!service) {
    return next(new ErrorResponse(`Service not found with id of ${req.params.id}`, 404));
}

// Make sure user adding service is business owner
if (service.user.toString() !== req.user.id && req.user.role !== 'admin') {
    return next(
        new ErrorResponse(
            `User ${req.user.id} is not authorized to update this service to business ${service._id}`,
            401
        )
    );
}

// File Upload validation
if (!req.files) {
    return next(new ErrorResponse(`Please upload a file.`, 400));
}

const file = req.files.file;

// Make sure it is a valid image file
if (!file.mimetype.startsWith('image')) {
    return next(new ErrorResponse(`Please upload a valid image file.`, 400));
}

//Check File Size
if (file.size > process.env.MAX_FILE_UPLOAD) {
    return next(
        new ErrorResponse(
            `Please upload an image less then ${process.env.MAX_FILE_UPLOAD / 1024}KB in size.`,
            400
        )
    );
}

// Create custom filename
file.name = `service-uploads/servicePhoto_${service._id}${path.parse(file.name).ext}`;

uploadToS3({
    fileData: req.files.file.data,
    fileName: file.name,
})
    .then(async (result) => {
        console.log('Success Result: ', result);

        await Service.findByIdAndUpdate(service._id, { photo: result.Location });

        return res
            .status(200)
            .json({ success: true, message: 'Service photo added successfully', url:    result.Location });
    })
    .catch((err) => {
        console.log(err);
        return next(new ErrorResponse('Failed to upload file to S3', 500));
    });
  });

我的实用程序文件将文件上传到 S3:

const AWS = require('aws-sdk');

const uploadToS3 = (options) => {
// Set the AWS Configuration
AWS.config.update({
    accessKeyId: process.env.AWS_S3_ACCESS_KEY,
    secretAccessKey: process.env.AWS_S3_SECRET_KEY,
    region: 'us-east-2',
});

// Create S3 service object
const s3 = new AWS.S3({ apiVersion: '2006-03-01' });

// Setting up S3 upload parameters
const params = {
    Bucket: 'toolbox-uploads',
    Key: options.fileName, // File name you want to save as in S3
    Body: options.fileData, //
};

// Return S3 uploading function as a promise so return url can be handled properly
return s3.upload(params).promise();
};

module.exports = uploadToS3;

我的路由器:

const express = require('express');
const {
 servicePhotoUpload
} = require('../controllers/service');

const Service = require('../models/Service');

router.route('/:id/photo').put(protect, authorize('publisher', 'business', 'admin'),  servicePhotoUpload);
 module.exports = router;

上面的代码是 100% 工作的。

我有点困惑,因为有不同的方法,谷歌和堆栈溢出都没有对我有用,而且他们都没有得到返回 url 并保存到数据库中。

我想制作单独的实用程序文件以将多个文件上传到 3,就像我对单个文件所做的一样,以便在任何地方使用它们。该文件应返回上传的网址,以便我可以更新我的数据库。我试过multer-s3,但没有解决方案适合我。

维克多·奥弗兰克

这种方法对您来说可能有所不同,但这就是我能够解决相同问题的方式。

首先你需要

  • 穆特
  • multer-s3
  • aws-sdk

我创建了一个FileUpload类来处理单个和多个上传(我还需要能够上传 pdf 和视频文件),这是我的构造函数中的代码,请注意,我还从 aws 中指定了有问题的 s3-bucket。

this.s3 = new AWS.S3({
        accessKeyId: process.env.S3_ACCESS_KEY_ID,
        secretAccessKey: process.env.S3_SECRET_KEY,
        Bucket: 'name_of_s3_bucket',
    });

我在类中创建了一个名为 upload 的方法。下面的代码

 upload(path, type) {
    let ext = 'jpeg';
    const multerFilter = (req, file, cb) => {
        if (type === 'image') {
            if (file.mimetype.startsWith(this.type)) {
                cb(null, true);
            } else {
                cb(
                    new AppError(
                        'Not an Image! Please upload only images',
                        400
                    ),
                    false
                );
            }
        } else if (type === 'pdf') {
            ext = 'pdf';
            const isPdf = file.mimetype.split('/')[1];
            if (isPdf.startsWith(this.type)) {
                cb(null, true);
            } else {
                cb(
                    new AppError('Not a pdf! Please upload only pdf', 400),
                    false
                );
            }
        }
    };

    const upload = multer({
        storage: multers3({
            acl: 'public-read',
            s3: this.s3,
            bucket: 'name_of_s3_bucket',
            metadata: function (req, file, cb) {
                cb(null, { fieldName: file.fieldname });
            },
            key: function (req, file, cb) {
                let filename = `user-${
                    req.user.id
                }/${path}/${uuid.v4()}-${Date.now()}.${ext}`;
                // eslint-disable-next-line camelcase
                const paths_with_sub_folders = [
                    'auditions',
                    'biography',
                    'movies',
                ];
                if (paths_with_sub_folders.includes(path)) {
                    filename = `user-${req.user.id}/${path}/${
                        req.params.id
                    }/${uuid.v4()}-${Date.now()}.${ext}`;
                }
                cb(null, filename);
            },
        }),
        fileFilter: multerFilter,
        limits: {
            fileSize: 5000000,
        },
    });

    return upload;
}

为了使用上述内容,我将该类导入到需要上传功能并调用以下内容的任何控制器中。

旁注:忽略路径代码(这只是为文件生成唯一文件名的一种方式)

const upload = new FileUpload('image').upload('profile-images', 'image');
exports.uploadUserPhoto = upload.array('photos', 10);

然后我使用uploadUserPhoto作为中间件,然后调用以下

exports.addToDB = catchAsync(async (req, res, next) => {
if (!req.files) return next();
req.body.photos = [];
Promise.all(
    req.files.map(async (file, i) => {
        req.body.photos.push(file.key);
    })
);

next();

});

在高级概述中,这是流程,首先,将您的照片上传到 s3 并获取 req.files,然后查看该 req.files 对象,将它们传递到您的 req 对象上的数组字段中,最后将它们保存在您的D B。

注意:您必须保证 req.file 循环,因为任务是异步的

我的最终路由器看起来像这样

router
.route('/:id')
.put(uploadUserPhoto, addToDB, updateProfile)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Pulumi(TypeScript,AWS):如何将多个文件上传到 S3,包括。静态网站托管目录中的嵌套文件

如何将图像上传到AWS S3并获取图像文件的S3存储桶URL并一次保存到dynamodb-Android

在将文件保存到数据库之前,如何在 Django 中压缩多个上传的文件?

如何将文件上传到 Laravel 中的 Amazon S3 预签名 URL?

如何将文件上传到AWS中的预签名URL?

如何将多个文件上传到C#中并在MVC中循环通过它们

使用NodeJS将多个文件上传到AWS S3

如何将多个文件上传到Firebase?

想要将图像保存到文件夹并将URL保存在数据库中

DreamFactory:如何将图像上传到文件服务器并将图像的路径保存在数据库中?

如何将用户窗口限制为文件上传到 AWS 中的 S3

c#如何将多个文件上传到SQL Server数据库?

如何按arraylist中的顺序将多个文件上传到firebase数据库?

将多个图像上传到Firebase存储并将下载URL保存到Android Studio Kotlin中的实时数据库

如何将文件上传到 django 数据库

如何将文件上传到CKAN扩展中的包?

如何将多个文件从目录上传到 S3?

如何将多个图像从文件夹上传到 S3 Bucket?

如何将文件上传到AWS S3存储桶?

文本区域字段中的多个URL链接并将其保存到数据库中

如何将文件上传到Dynamics?

如何将文件上传到API

将文件从AWS Lambda(Python)中的多部分/表单数据上传到S3

Blueimp jQuery File Uploader并将文件大小保存到数据库中

从数据库中删除记录并将它们保存到文件 - PHP

如何将PHP会话数据保存到数据库而不是文件系统中?

如何将图像上传到AWS S3

如何使用数据库中的保存URL上传文件

Rails:无法从 URL 保存文件并将其保存到 Amazon S3 (S3::Error::ResponseError)