Search code examples
mongodbmongoosenext.jsgridfsgridfs-stream

gridfs-stream Image in Next js


In "pages/api", trying to print out GridFS images from MongoDB database on the client. Works in (another) MERN-Stack project but seems that I have a problem in Next.js.

pages/api/uploads/files/index.js Works(I'm getting the returned files in the client-side):

    import Grid from 'gridfs-stream'
    Grid.mongo = mongoose.mongo;

    export default async function handler(req, res) {
        const { method } = req
    
        const conn = await mongoose.createConnection(db, {
            useNewUrlParser: true,
            useUnifiedTopology: true
        });
    
        switch (method) {
            case 'GET':
                try {
                    const files = await conn.db.collection("uploads.files").find().toArray()
                    if(!files || files.length === 0) {
                        return res.status(404).json({ err: 'No file exist' });
                    } else {
                        files.map(file => {
                            if (
                                file.contentType === 'image/jpeg' ||
                                file.contentType === 'image/jpg' ||
                                file.contentType === 'image/png'
                            ) {
                                file.isImage = true;
                            } else {
                                file.isImage = false;
                            }
                        });
                        return res.send(files);
                    }
                } catch (error) {
                    res.status(400).json({ itemnotfound: "No file found" })
                }
                break
            default:
                res.status(400).json({ itemnotfound: "No file" })
            break
        }
    }

pages/api/uploads/image/[filename].js The issue(it logs "1 API / 3 API")

import Grid from 'gridfs-stream'
Grid.mongo = mongoose.mongo;

export default async function handler(req, res) {        
    const {
      query: { filename },
      method,
    } = req
    
    const conn = await mongoose.createConnection(db, {
        useNewUrlParser: true,
        useUnifiedTopology: true
    });

    conn.once('open', () => {
        gfs = Grid(conn.db);
        gfs.collection('uploads');
    });

    switch (method) {
        case 'GET':
            try {
                const file = await conn.db.collection("uploads.files").findOne({ filename: filename })
                if(!file || file.length === 0){
                    return res.status(404).json({ err: "Could not find file" });
                } else if(
                    file.contentType === 'image/jpeg' ||
                    file.contentType === 'image/jpg' ||
                    file.contentType === 'image/png'
                ) {
                    console.log("1 API ", file) // gets printed out
                    const readstream = gfs.createReadStream(file.filename);
                    readstream.pipe(res);
                } else {
                    console.log("2 API")
                    res.status(404).json({ err: 'Not an image' });
                }
            } catch (error) {
                console.log("3 API")  // after "1 API", this gets called
                res.status(400).json({ itemnotfound: "No image found" })
            }
            break
        default:
            res.status(400).json({ itemnotfound: "No image" })
        break
    }
}

In the client side I have an img tag that waits for the image:

pages/index.js

<img key={f.uploadDate} src={`/api/uploads/image/${f.filename}`} alt={f.filename} width="50" height="50"></img>

It's probably a problem with readstream.pipe(res), since console.log prints out "1 API"(and the file) and then "3 API", but I cannot find out what.

Thanks in advance!


Solution

  • Found the Issue. The following line doesn't work:

    conn.once('open', () => {...})
    

    Apparently, 'open()' is deprecated and you can find more information here: https://github.com/Automattic/mongoose/issues/5399

    So I just delete it but kept the lines that were inside in the outher block:

    ...
    const conn = await mongoose.createConnection(db, {
        useNewUrlParser: true,
        useUnifiedTopology: true
    });
    
    gfs = Grid(conn.db);
    gfs.collection('uploads');
    
    switch (method) {
    ...