Search code examples
javascriptmongoosegraphqlapollo-servergridfs-stream

Uploading files with graphql to mongodb with mongoose


I want to upload file to mongodb with graphql resolver. In server.js I have this help function to store file, which is exported to use it in my resolver. The function is basing on what I found here: https://github.com/jaydenseric/graphql-upload/issues/8), but now some things have changed in graphql. For example destructurising file object. I don't know what should be found at path variable and how should I use this createReadStream(function which was destructurized from file).

const mongoose = require('mongoose');
const Grid = require('gridfs-stream');
const fs = require('fs');

//...

// Connect to Mongo
mongoose
  .connect(process.env.mongoURI, {
    useNewUrlParser: true,
    useCreateIndex: true,
    useUnifiedTopology: true,
    useFindAndModify: false
  }) // Adding new mongo url parser
  .then(() => console.log('MongoDB Connected...'))
  .catch(err => console.log(err));




const storeFile = async (upload) => {
   const { filename, createReadStream, mimetype } = await upload.then(result => result);

   const bucket = new mongoose.mongo.GridFSBucket(mongoose.connection.db, { bucketName: 'files' });

   const uploadStream = bucket.openUploadStream(filename, {
     contentType: mimetype
   });
   createReadStream()
     .pipe(uploadStream)
     .on('error', console.log('error'))
     .on('finish', console.log('finish'));
 }

module.exports = { storeFile }
//...

My resolver(here it's minimal version, because now I want only to upload file into my database. In one of my tries, it even created fs.files and fs.chunks collections, but without a data):

Mutation: {
    uploadFile: async (_, { file }) => {
      console.log(file);
      const fileId = await storeFile(file);

      return true;
     
    }
  }

I have this error now:

Unhandled Rejection (Error): GraphQL error: The "listener" argument must be of type function. Received undefined

and in terminal I have printed 'error'(like in pipe.on('error', console.log('error') statement )

And I can upload only small files( max 60 kb), all larger just don't upload, but errors are showing on all tries.


Solution

  • Ok, I managed to solve it.

    resolver mutation:

    const { storeFile } = require('../../server');
    //...
    
    uploadFile: async (_, { file }) => {
          const fileId = await storeFile(file).then(result => result);
    
          return true;
    // later I will return something more and create some object etc.
        }
    

    supporting function from server.js

     const storeFile = async (upload) => {
        const { filename, createReadStream, mimetype } = await upload.then(result => result);
    
        const bucket = new mongoose.mongo.GridFSBucket(mongoose.connection.db, { bucketName: 'files' });
        
        const uploadStream = bucket.openUploadStream(filename, {
          contentType: mimetype
        });
        return new Promise((resolve, reject) => {
          createReadStream()
            .pipe(uploadStream)
            .on('error', reject)
            .on('finish', () => {
                resolve(uploadStream.id)
            })
        })
      }
    
      module.exports = { storeFile }