Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using GridFS #8

Closed
cristiandley opened this issue Jul 4, 2017 · 3 comments
Closed

Using GridFS #8

cristiandley opened this issue Jul 4, 2017 · 3 comments
Labels

Comments

@cristiandley
Copy link

Hi guys, awesome project, i used it with the default conf and works great. But... im dealing with a new path and it is to use GridFS.

How i can connect it to GridFS ?.

Maybe im a bit loose.

Sorry im asking it here.

@jaydenseric
Copy link
Owner

I use MongoDB GridFS too.

Here is an example with auth, additional metadata, etc. stripped out...

In your model:

import { createReadStream, unlink } from 'fs'
import { ObjectId, GridFSBucket } from 'mongodb'
import { connect } from './db'

export async function getFileById(fileId) {
  const db = await connect
  const file = await db.collection('fs.files').findOne(ObjectId(fileId))
  if (!file) throw new Error(`Failed to retrieve file with ID “${fileId}”.`)
  return file
}

export async function storeFile({ name, type, path }) {
  const db = await connect
  const bucket = new GridFSBucket(db)
  const uploadStream = bucket.openUploadStream(name, {
    contentType: type
  })

  return new Promise((resolve, reject) => {
    createReadStream(path)
      .pipe(uploadStream)
      .on('error', reject)
      .on('finish', () => {
        // Delete the upload temp file
        unlink(path, () => {
          // Resolve the stored file ObjectId
          resolve(uploadStream.id)
        })
      })
  })
}

In your resolvers:

import { storeFile, getFileById } from './model'

export default {
  Mutation: {
    async uploadFile(root, { file }) {
      const fileId = await storeFile(file)
      return getFileById(fileId)
    }
  }
}

I use MongoDB Cloud Atlas, which means this approach is a bit inefficient. The file uploads to our API server, then it gets uploaded from there a second time to GridFS in the cloud. In theory, you could stream the upload directly to GridFS and skip storing the file on the API server. That would also mean your resolvers can't validate the file before it gets inserted in the DB. It would also involve a major update to apollo-upload-server.

When I get the time I intend to implement a bespoke multipart form parser that would pass normal variables into the resolvers like now, but files will be streams instead of a path. So it will be up you to stream it wherever you like in the resolver. This will enable a lot of flexibility.

@cristiandley
Copy link
Author

You Rock! @jaydenseric

@cristiandley
Copy link
Author

@jaydenseric just to let some data for future readers. This is how i did it with Mongoose:

     guardarArchivo({ name, type, path }) {
		let writestream = Grid(
			mongoose.connection.db,
			mongoose.mongo
		).createWriteStream({
			filename: name
		});

		fs.createReadStream(path).pipe(writestream);

		writestream.on("close", file => {
			console.log(file.filename + "Almacenado");
		});
	}

Have a great day!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants