Playing an audio file stored on MongoDB Atlas

55 Views Asked by At

I have an app on Heroku, handling audio files stored with GridFS in a database on MongoDB Atlas.

This app uses Next.JS and express.

For the sake of the question, let us consider this record that I have on MongoDB Atlas in the collection fs.files.

_id: 46e737001837a062ce85dd4c
length: 214023
chunkSize: 261120
uploadDate: 2023-08-12T05:09:22.521+00:00
filename: "Audio_2023-09-18:14:39:26"

The code below (Block:server.get('/download', (req, res) => {...}), part of the file server.js, will be the object of my question:

const express = require('express'),
            next = require('next'),
      .....
      mongoose = require('mongoose'),
      Grid = require('gridfs-stream'),
      mongoURI = process.env.MDB_URI_AUDIO;

mongoose.connect(mongoURI);

.....


const conn = mongoose.connection;

let gfs; // GridFS stream

conn.once('open', () => {
  // Initialize GridFS stream
  gfs = Grid(conn.db, mongoose.mongo);
});

.....


app.prepare().then(() => {
    const server = express();
  server.use(bodyParser.json({ limit: '1mb' }));

  .....

  server.get('/download', (req, res) => {
    const gridFSBucket = new mongoose.mongo.GridFSBucket(conn.db);
    const dataType = "audio/mp3";

    if (req.query.afn) {
      const filename = req.query.afn;
      const downloadStream = gridFSBucket.openDownloadStreamByName(filename);
       res.set('Content-Type', dataType); // Adjust the content type based on your audio format
      res.set('Content-Disposition', `inline; filename="${filename}"`);
      downloadStream.pipe(res)
    }

    if (req.query.id) {
      // const recordID = req.query.id.toString(); // This does not work !
      // const recordID = new ObjectID(req.query.id); // This does not work !
      // const recordID = mongoose.Types.ObjectID(req.query.id); // This does not work !
      const recordID = mongoose.Types.ObjectID.from(req.query.id); // This does not work !
      const downloadStream = gridFSBucket.openDownloadStream(recordID);
      res.set('Content-Type', dataType)
      res.set('Content-Disposition', `inline; filename=BLABLAH`);
      downloadStream.pipe(res);
    }
  });

  .....

  // Default route handler for Next.js pages
  server.all('*', (req, res) => {
    return handle(req, res);
  });


  const PORT = process.env.PORT || 3000; // Use Heroku-assigned port or default to 3000.

  server.listen(PORT, (err) => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${PORT}`);
  });
});

When I point my browser to this address:

https://myapp.herokuapp.com/download?afn=Audio_2023-09-18:14:39:26

I hear the audio file being played. And this is what I expect.

When I point my browser to this other address:

https://myapp.herokuapp.com/download?id=46e737001837a062ce85dd4c

I expect the same thing as with the first link, but it does not happen (I hear nothing and get errors). With the first link I am using the file name to get the audio, with the second link I am using the file ID to get it.

There is most probably an issue in this part of my code. But what am I missing and doing wrong?

if (req.query.id) {
  .....
}

I hope somebody will shed some light on this issue and help me solve the problem.

1

There are 1 best solutions below

2
Alex Blex On

You need to debug it.

I am not convinced that

const recordID = mongoose.Types.ObjectID.from(req.query.id); 

returns an ObjectID.

https://www.mongodb.com/docs/drivers/node/v3.6/fundamentals/gridfs/ uses native constructor in their example:

const recordID = ObjectId(req.query.id); 

And if I understand https://github.com/Automattic/mongoose/blob/ec4191ee9c3b641ab4005b119c6949002088bcb1/types/types.d.ts#L83 mongoose.Types.ObjectID doesn't add much to native ObjectId.