简体   繁体   English

FileStream从busboy到MongoDB

[英]FileStream from busboy to MongoDB

So I have an incoming FileStream from busboy that I want to save to MongoDB. 所以我有一个从busboy传入的FileStream,我想保存到MongoDB。 I think I need to have it as a File or some sort of buffer to be able to save it. 我想我需要将其作为File或某种缓冲区来保存。 I'm sure I could do it by first saving it to disk using fs and then reading it, but that seems cumbersome. 我敢肯定,可以先通过fs将其保存到磁盘上,然后再读取它来完成此操作,但这似乎很麻烦。 This is my full route code so far: 到目前为止,这是我的完整路由代码:

// Upload a new study plan
router.route("/add").post((req, res, next) => {
    let busboy = new Busboy({headers: req.headers});

    // A field was recieved
    busboy.on('field', function (fieldname, val, valTruncated, keyTruncated) {

        if (req.body.hasOwnProperty(fieldname)) { // Handle arrays
            if (Array.isArray(req.body[fieldname])) {
                req.body[fieldname].push(val);
            } else {
                req.body[fieldname] = [req.body[fieldname], val];
            }
        } else { // Else, add field and value to body
            req.body[fieldname] = val;
        }
    });

    // A file was recieved
    busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
        const saveTo = path.join('.', filename);
        let readFile = null;

        file.on("data", () => {
            console.log("Got file data!");
        })

        file.on("end", () => {
            //How do I save the file to MongoDB?
        })
    });

    // We're done here boys!
    busboy.on('finish', function () {
        //console.log(req.body);
        console.log('Upload complete');
        res.end("That's all folks!");
    });
    return req.pipe(busboy);
});

I want to append {"pdf": file} to my req.body which has the rest of the data... 我想将{"pdf": file}附加到具有其余数据的req.body中...

There's no need for saving your file to disk, you can stream it directly from busboy to mongo with some kind of a streaming interface - I'm not sure how you wish to save the file, but if that's just a simple file structure I guess you should use Mongo's GridFS . 无需将文件保存到磁盘,您可以使用某种流接口将文件直接从busboy传输到mongo-我不确定您希望如何保存文件,但是我想如果这只是一个简单的文件结构您应该使用Mongo的GridFS

I assume you got your connection and client from somewhere, so we'll just use that. 我假设您是从某个地方获得连接和客户端的,所以我们就使用它。 We need a GridFS bucket from the cliet: 我们需要一个GridFS存储桶:

const db = client.db(dbName);
const bucket = new mongodb.GridFSBucket(db);

We'll use it when we want to save the file: 当我们要保存文件时,将使用它:

    // A file was recieved
    busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
        const saveTo = path.join('.', filename);
        // here we PIPE the file to DB.
        file.pipe(bucket.openUploadStream(saveTo));
    });

Now there's also a matter of responding when the files are actually saved - as this is done asynchronously. 现在还有一个问题是何时实际保存文件-因为这是异步完成的。 So we need to keep count of running operations like this: 因此,我们需要保持这样的运行操作计数:

    // place this in the request callback.
    // here's our counter - we'll increment it for each operation started.
    let ops = 0;
    const dec = () => --ops || res.end("That's all folks!");

Now we change the code above a little so we won't respond until the files are saved in Mongo: 现在,我们将上面的代码稍作更改,以便在文件保存到Mongo中之前不会做出响应:

    // A file was recieved
    busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
        ops++; // we increment ops for each file saved
        const saveTo = path.join('.', filename);
        // here we PIPE the file to DB (pass the db and collection here).
        file.pipe(bucket.openUploadStream(saveTo))
            .on('finish', dec);
    });

    ops++; // we're waiting for finish of the request also so another increment
    busboy.on('finish', dec);

As you see every time a file upload is started we increment the ops and when it's finished, we decrement it. 如您所见,每次文件上传开始时,我们都会增加操作次数,完成后我们会减少操作次数。 The || || operator will execute the res.end method when ops reach 0 . ops达到0时, ops员将执行res.end方法。

So while Michal's answer is probably not wrong, it was not what I was after. 因此,尽管Michal的答案可能没有错,但这并不是我所追求的。 I finally found a solution by using the Buffer object. 我终于找到了使用Buffer对象的解决方案。 Here is my code: 这是我的代码:

router.route("/add").post((req, res, next) => {
    let busboy = new Busboy({headers: req.headers});
    let buffers = [];

    // A field was recieved
    busboy.on('field', function (fieldname, val, valTruncated, keyTruncated) {

        if (req.body.hasOwnProperty(fieldname)) { // Handle arrays
            if (Array.isArray(req.body[fieldname])) {
                req.body[fieldname].push(val);
            } else {
                req.body[fieldname] = [req.body[fieldname], val];
            }
        } else { // Else, add field and value to body
            req.body[fieldname] = val;
        }
    });

    // A file was recieved
    busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {

        file.on("data", (data) => {
            buffers.push(data);
        });

        file.on("end", () => {
            req.body[fieldname] = Buffer.concat(buffers);
        });
    });

    // We're done here boys!
    busboy.on('finish', function () {
        console.log(req.body);

        const plan = new StudyPlan(req.body);
        plan.save()
            .then(_ => console.log("YEEAEH!"))
            .catch(err => {console.log(err);});

        res.end();
    });
    return req.pipe(busboy);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM