What if I know the mongo id of a file stored in gridFS, and want to download it under the filename that is stored in its fs.files filename field? I don't have a model to call the collection with, so I'm confused how I'm supposed to do a query on that collection.
This is my server.js file, where I connect to the database:
require('dotenv').config()
const mongoose = require('mongoose')
//connect to mongoose
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true })
.then(() => {
// Listen for requests
app.listen(process.env.PORT, () => {
console.log(`Connected to MongoDB and listening on port`, process.env.PORT)
})
})
.catch((error) => {
//throws error if the MONGO_URI string has the wrong user or pw
console.log(error)
})
and in my files controllers file I have this:
const mongoose = require('mongoose')
require('dotenv').config()
const fs = require('fs')
//Create a bucket for storing files
//bucket is initialized to fs and has 2 collections: fs.files and fs.chunks
let bucket
let conn
mongoose.connection.on("connected", () => {
conn = mongoose.connections[0].db
bucket = new mongoose.mongo.GridFSBucket(conn)
})
const downloadFileByID = async (req, res) => {
const { id } = req.params
if (!mongoose.Types.ObjectId.isValid(id)){
return res.status(404).json({error: 'No such file'})
}
const mongooseID = new mongoose.Types.ObjectId(id)
//Get filename
const cursor = bucket.find({}) //find() returns a FindCursor iterable
let filename
for await (const file of cursor) {
if (file._id == id){
filename = file.filename
}
}
try{
bucket.openDownloadStream(mongooseID).pipe(fs.createWriteStream('./'+ filename.filename))
res.send(filename)
} catch (error) {
res.status(400).json({error: "File not found, file ID does not exist"})
}
}
The loop I do to find the filename is not optimal and very slow, but I haven't found another way to access the filename field of fs.files.
Doing bucket.find({_id: id})
doesn't seem to actually find the file, it returns nothing (I don't think find() takes any arguments). However, the documentations state that there should be a way to get the filename field from the fs.files collection, but doesn't explain how to do it. I'm pretty stuck on this...
Otherwise, I also tried directly querying from the fs.files collection, but since I have no model for that collection, I don't have a model name to do the query on. Most sources use a syntax similar to `db.fs.files.findOne({_id: id}), but I get an error saying that db is not defined. This issue seems easy to solve, but I've been stuck for days. Any help would be so appreciated.
I have solved my problem! The answer was pretty simple, as expected:
const files = conn.collection('fs.files')
const filename = await files.findOne({_id: mongooseID}, {projection:{filename : 1, _id : 0}})