NodeJS - MongoDB - Ajax多文件上传和保存DB无法正常工作的路径

时间:2016-11-22 06:20:04

标签: node.js mongodb express

我正在向NodeJS服务器上传多个PDF Ajax并保存MongoDB Book文档的路径。

问题是当我第一次上传多个文件时,只有一个书籍路径被保存到MongoDB文档中,其他文件被正确上载,我可以在uploads目录中查看,但没有得到保存到文档中。

我知道,这个问题与NodeJS中的异步进程有关。但我不知道如何解决这个问题。

以下是上传文件和保存MongoDB文档路径的代码。

var express = require('express')
var formidable = require('formidable')
var Book = require('../models/book')
var router = express.Router()
var path = require('path')
var uploadDir = path.join(__dirname, '/../uploads/')
var uploadDir2 = path.join(__dirname, '/..')
var imageDir = path.join(__dirname, '/../uploads/images/')
var exec = require('child_process').exec

router.post('/api/upload', function (req, res, next) {
  var email = req.user.email
  var form = new formidable.IncomingForm()
  form.multiples = true
  form.keepExtensions = true
  form.uploadDir = uploadDir

  form.parse(req, (err, fields, files) => {
    if (err) return res.status(500).json({ error: err })
    if (Array.isArray(files.userBooks)) {
      files.userBooks.forEach(function (item, index) {
        // bookPath.push(item.path.split('LibreRead')[1])
        item = item.path.split('LibreRead')[1]
        saveBooks(item)
        getCover(item)
      })
    } else {
      var item = files.userBooks.path.split('LibreRead')[1]
      saveBooks(item)
      getCover(item)
    }

    function saveBooks (bookPath) {
      Book.find({email: req.user.email}, function (err, content) {
        if (err) console.error(err)
        var coverPath = '/uploads/images/' + bookPath.split('/uploads/').pop() + '-001-000.png'
        var list = [{bookPath: bookPath, coverPath: coverPath}]

        if (!content.length) {
          var b = new Book({email: email, list: [list]})
          return b.save(function (err, content) {
            if (err) return console.log(err)
            console.log(content)
          })
        } else {
          content[0].list.push(list)
          return content[0].save(function (err, content) {
            if (err) return console.error(err)
            console.log(content)
          })
        }
      })
    }

    function getCover (bookPath) {
      var cmd = 'pdfimages -p -png -f 1 -l 2 ' + uploadDir2 + bookPath + ' ' + imageDir + bookPath.split('/uploads/').pop()
      return exec(cmd, function (err, stdout, stderr) {
        if (err) return console.error(err)
        console.log(stdout)
      })
    }

    res.redirect('/')
  })
  form.on('fileBegin', function (name, file) {
    const [fileName, fileExt] = file.name.split('.')
    file.path = path.join(uploadDir, `${fileName}_${new Date().getTime()}.${fileExt}`)
  })
})

module.exports = router

我认为forEach循环是同步/阻塞,但仍然只保存了一个文件路径,其他文件路径不存在于MongoDB中

任何帮助对我都有用。谢谢!

1 个答案:

答案 0 :(得分:0)

我认为是时间问题,因为您在响应重定向之前没有等待所有保存过程完成。

您可以使用Promise解决此问题(如果您的nodejs版本支持es6,或者npm安装bluebird)

router.post('/api/upload', function (req, res, next) {
    var email = req.user.email
    var form = new formidable.IncomingForm()
    form.multiples = true
    form.keepExtensions = true
    form.uploadDir = uploadDir

    form.parse(req, (err, fields, files) => {
        if (err) return res.status(500).json({ error: err })

        var promise;
        if (Array.isArray(files.userBooks)) {
            promise = Promise.all(files.userBooks.map(function (item, index) {
                // bookPath.push(item.path.split('LibreRead')[1])
                item = item.path.split('LibreRead')[1]
                return saveAndReturnCover(item)
            })).then(function(covers) {
                // do something with the results if you want to
            })
        } else {
            var item = files.userBooks.path.split('LibreRead')[1]
            promise = saveAndReturnCover(item)                
        }
        promise.then(function () {
            res.redirect('/')
        })

        function saveAndReturnCover(item) {
            return saveBooks(item).then(function () {
                return getCover(item)
            })
        }

        function saveBooks(bookPath) {
            return new Promise(function (resolve, reject) {
                Book.find({ email: req.user.email }, function (err, content) {
                    if (err) {
                        console.error(err)
                        return reject(err)
                    }
                    var coverPath = '/uploads/images/' + bookPath.split('/uploads/').pop() + '-001-000.png'
                    var list = [{ bookPath: bookPath, coverPath: coverPath }]

                    if (!content.length) {
                        var b = new Book({ email: email, list: [list] })
                        return b.save(function (err, content) { // no idea what .save will return
                            if (err) {
                                console.log(err)
                                return reject(err)
                            }
                            console.log(content)
                            resolve(content)
                        })
                    } else {
                        content[0].list.push(list)
                        return content[0].save(function (err, content) { // no idea what .save will return
                            if (err) {
                                console.error(err)
                                return reject(err)
                            }
                            console.log(content)
                            resolve(content)
                        })
                    }
                })
            })
        }

        function getCover(bookPath) {
            return new Promise(function (resolve, reject) {
                var cmd = 'pdfimages -p -png -f 1 -l 2 ' + uploadDir2 + bookPath + ' ' + imageDir + bookPath.split('/uploads/').pop()
                return exec(cmd, function (err, stdout, stderr) {
                    if (err) {
                        console.error(err)
                        reject(err)
                    } 
                    console.log(stdout)
                    resolve(stdout)
                })
            })
        }        
    })
    form.on('fileBegin', function (name, file) {
        const [fileName, fileExt] = file.name.split('.')
        file.path = path.join(uploadDir, `${fileName}_${new Date().getTime()}.${fileExt}`)
    })
})