node + express 使用 MongoDB 保存下载文件

初衷:使用本地文件存储方式管理起来比较复杂, 目录混乱.
目的:使用mongodb自带文件存储功能,进行文件读取写入.

注:仅仅是功能的实现不考虑是否最优(希望是).

上传文件

  • 一个基本的配置文件mongoose.js.
const mongoose = require('mongoose')
const env = require('../enviroment/env')
mongoose.connect(env.mongoURL, {
    useNewUrlParser: true,
    useCreateIndex: true,
    useUnifiedTopology: true,
    useFindAndModify: false
})
mongoose.connection.on('error', (err) => {
    console.error('数据库连接出错:' + err)
})
mongoose.connection.on('connected', () => {
    console.log('数据库已连接:' + env.mongoURL)
})
module.exports = mongoose

需要处理post文件中间件:connect-busboy,方便直接获取文件流.

const busboy = require('connect-busboy');
app.use(busboy());

具体处理请求controller :

   try {
            const busboy = req.busboy;
            req.pipe(busboy);
            let file = await fileService.upLoad(busboy, req)
            res.send(file);
        } catch (error) {
            res.status(500).send(error.toString());
       }

以上步骤已经可以获取上传的文件流,接下来需要将流写入到mongodb.
因为mongodb的文件存储不是通过自定义model来写入的,必须用到mongoose 的配置文件,进行文件操作(个人理解).

const mongoose = require('../db/mongoose')
const conn = mongoose.connection;

busboy.on('file', async function (fieldname, file, filename, encoding, mimetype) {
                let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
                    chunkSizeBytes: 1024 * 255
                });
                let user = req.user
                //自己添加的信息
                const metadata = {
                    ownerID: user._id,
                }
                let bucketStream = bucket.openUploadStream(filename, { metadata })
                bucketStream.on("error", async (e) => {
                    await removeChunks(bucketStream);
                    throw new Error('SaveBlogImg BucketStream Error')
                })

                req.on("aborted", async () => {
                    console.log("Upload Request Cancelling...");
                    await removeChunks(bucketStream);
                })

                file.pipe(bucketStream)
                
                // file:数据库保存后的内容
                bucketStream.on("finish", async (file) => {}
                })

通过以上步骤已经可以保存上传的文件到mongodb中,使用可视化工具查看数据库可以看到新添加的集合fs.chunksfs.files,还有一个GridFS Bucket.只要删除了后者的文件内容fs.chunksfs.files里面对应的文件都会被删除.注意力集中到fs.files,平时我们操作文件都是通过这个集合来入手的.

下载文件

可以通过fs.files查询到文件内容的id与name,再通过它获取文件.

 const ObjectID = require('mongodb').ObjectID
 let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
            chunkSizeBytes: 1024 * 255
        })
 let readeStream = bucket.openDownloadStream(ObjectID(id))

其他

使用到文件保存处理更多的是涉及图片的内容,配合mongodb读取图片内容可以使用npm工具sharpconcat-stream.前者可以处理图片的大小,后者可以把stream转成buffer类型,当然它们的功能不仅仅如此,更多的需要你去发现.

你可能感兴趣的:(笔记)