【问题标题】:Creating a read stream to a directory and piping entire directory to MongoDB Bucket创建到目录的读取流并将整个目录通过管道传输到 MongoDB Bucket
【发布时间】:2020-01-12 15:44:00
【问题描述】:

我正在尝试将整个目录保存到 MongoDB 存储桶

当我压缩文件时它可以工作,但我需要将文件解压缩到存储桶中。

当我尝试流式传输目录时,错误显示为 "Illegal operation on a directory"

我一直在尝试寻找解决方案,但找不到用于目录的解决方案。

let conn = mongoose.connection;
let gfb;

conn.once('open', () => {
  //init the stream
  console.log('- Connection open -');
  gfb = new mongoose.mongo.GridFSBucket(conn.db, {
    chunkSizeBytes: 1024,
    bucketName: 'uploads'
  })
})

const uploaddb = (req, res, vile) => {
conn.once('open', () => {
    console.log('- Connection open -');
    gfb = new mongoose.mongo.GridFSBucket(conn.db, {
      chunkSizeBytes: 1024,
      bucketName: 'uploads'
    })
    try {
    uploadDir('/Users/nancycollins/virtuload-beta/backend/uploads/unzipped/')
    } catch (e) {
      console.error(e);
    }
  });
}

async function uploadDir (folder, subFolder = '') {
  const actualFolder = path.join(folder, subFolder)
  const contents = await fs.readdir(actualFolder, { withFileTypes: true })
  await Promise.all(contents.map((fileOrDirectory) =>
    fileOrDirectory.isDirectory()
      ? uploadDir(folder, path.join(subFolder, fileOrDirectory.name))
      : uploadFile(folder, path.join(actualFolder, fileOrDirectory.name))
  ))
}

async function uploadFile (baseFolder, filePath) {
  return new Promise((resolve, reject) => {
    fs.createReadStream(filePath)
      .pipe(gfb.openUploadStream(filePath, { metadata: path.relative(baseFolder, filePath) }))
      .on('error', function(error) {
        reject(error);
      })
      .on('finish', () => {
        resolve()
      })
  })
}

-我也尝试将 try-catch 更改为:

    try {
    const folder = '/Users/nancycollins/virtuload-beta/backend/uploads/unzipped/';
    uploadDir(folder)
    } catch (e) {
      console.error(e);
    }

编辑:

这是更新版本。

当前错误为:

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type object
    at validateString (internal/validators.js:125:11)
    at Object.join (path.js:1147:7)

等等……

【问题讨论】:

  • 你不能那样做。你可以pipe一个目录下的所有文件,但不能是目录本身。
  • 好的,所以我想我可以在 MongoDB 中创建一个目录并将文件添加到其中?看到文件将是 html 和 js 文件,因此他们需要保持通信流。
  • 如果您需要保留一些结构,您可以上传文件并将其相关文件夹信息保存在metadata 字段中。
  • 我明白了,你能给我指出正确的方向吗?

标签: javascript node.js mongodb stream fs


【解决方案1】:

解决方法:

上传文件夹文件并将它们的相对文件夹结构保存在 GridFS 的metadata 中。在此示例中,uploadDir 是一个递归函数,它遍历给定文件夹及其子文件夹,并为找到的每个文件调用 uploadFile

在此示例中,我假设您使用的是fs 的承诺版本。

async function uploadDir (folder, subFolder = '') {
  const actualFolder = path.join(folder, subFolder)
  const contents = await fs.readdir(actualFolder, { withFileTypes: true })
  await Promise.all(contents.map((fileOrDirectory) =>
    fileOrDirectory.isDirectory()
      ? uploadDir(folder, path.join(subFolder, fileOrDirectory.name))
      : uploadFile(folder, path.join(actualFolder, fileOrDirectory.name))
  ))
}

async function uploadFile (baseFolder, filePath) {
  return new Promise((resolve, reject) => {
    fs.createReadStream(filePath)
      .pipe(gfb.openUploadStream(filePath, { metadata: path.relative(baseFolder, filePath) }))
      .on('error', function(error) {
        reject(error);
      })
      .on('finish', () => {
        resolve()
      })
  })
}

编辑:

如果您不需要存储更多信息,您可以将 GridFS 文件的 name 设置为相对路径。

【讨论】:

  • 这是一个绝妙的解决方案,谢谢。当您说将 GridFS 的文件名设置为相对路径时,您是什么意思?
  • 我也收到错误消息:“UnhandledPromiseRejectionWarning:TypeError [ERR_INVALID_ARG_TYPE]:“path”参数必须是字符串类型。在“const actualFolder = path.join(folder,子文件夹)”
  • Mmm 文件夹参数应该是绝对路径。此外,您只需要创建我在答案中发布的两个函数,然后从您原来的 uploaddb() 函数中调用 uploadDir('<absolutePath>')。然后,当 promise 解决后,您可以将响应发送给客户端。
  • 我已经尝试过了,对我来说效果很好,也许可以粘贴完整的堆栈跟踪?也可以使用uploadDir(folder).catch(console.error) 捕获它
猜你喜欢
  • 2014-08-07
  • 2021-05-25
  • 2018-06-04
  • 1970-01-01
  • 1970-01-01
  • 2020-09-02
  • 1970-01-01
  • 2011-03-15
  • 1970-01-01
相关资源
最近更新 更多