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.
You need to debug it.
I am not convinced that
returns an ObjectID.
https://www.mongodb.com/docs/drivers/node/v3.6/fundamentals/gridfs/ uses native constructor in their example:
And if I understand https://github.com/Automattic/mongoose/blob/ec4191ee9c3b641ab4005b119c6949002088bcb1/types/types.d.ts#L83
mongoose.Types.ObjectIDdoesn't add much to native ObjectId.