Skip to content
node

How to save images to MongoDB in Node.js

Dec 21, 2022Abhishek EH6 Min Read
How to save images to MongoDB in Node.js

In this article, we will see how to create APIs to upload an image and store them in MongoDB, list the images and download an image.

Project setup

Create a directory called node-mongo-image-upload and run the command npm run init inside it. This will initiate a Node.js project.

Install the following dependencies:

1npm i express multer dotenv multer-gridfs-storage
  • express to create APIs is Node.js.
  • multer to upload files.
  • dotenv - to store configurations like database URL.
  • multer-gridfs-storage to save the file uploaded via multer to MongoDB.

Create .env file and add the MongoDB URL in it:

1MONGO_DB_URL=mongodb://localhost:27017/images

Uploading file

Create a file named index.js with the following code:

index.js
1const express = require("express")
2const multer = require("multer")
3const { GridFsStorage } = require("multer-gridfs-storage")
4require("dotenv").config()
5
6const url = process.env.MONGO_DB_URL
7
8// Create a storage object with a given configuration
9const storage = new GridFsStorage({
10 url,
11 file: (req, file) => {
12 //If it is an image, save to photos bucket
13 if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
14 return {
15 bucketName: "photos",
16 filename: `${Date.now()}_${file.originalname}`,
17 }
18 } else {
19 //Otherwise save to default bucket
20 return `${Date.now()}_${file.originalname}`
21 }
22 },
23})
24
25// Set multer storage engine to the newly created object
26const upload = multer({ storage })
27
28const app = express()
29
30app.post("/upload/image", upload.single("avatar"), (req, res) => {
31 const file = req.file
32 // Respond with the file details
33 res.send({
34 message: "Uploaded",
35 id: file.id,
36 name: file.filename,
37 contentType: file.contentType,
38 })
39})
40
41const server = app.listen(process.env.PORT || 8765, function () {
42 const port = server.address().port
43
44 console.log("App started at port:", port)
45})

In the above code,

  • We are initializing the GridFs with the bucket name photos, whenever an image is uploaded, it will be saved to this bucket.
  • We are prefixing the file name with the date so that, each time a unique name is generated.
  • If it is not an image, then it will be saved to the default bucket called fs.
  • We have written a post route /upload/image, which will call the upload middleware.
  • The upload middleware will save the file sent at the parameter avatar.
  • Finally, we are responding with the uploaded file details.

Now start the application by running node index.js or nodemon.

Now in Postman, post an image to the endpoint http://localhost:8765/upload/image

Uploading a file in postman

If you click 'Send', you will receive uploaded image details in the response:

upload image postman

Now if you go and check the MongoDB, you will see the following collections created there:

mongo collections

fs.files and fs.chucks will be created when you upload files that are not images.

The photos.files collection will have the information about the uploaded images:

photos files

The photos.chunks collection will have the actual image data:

photos chunks

If the file size is larger, it will break into multiple chunks.

Listing uploaded files

You can list all the images by querying photos.files collection:

index.js
1const express = require("express")
2const multer = require("multer")
3const { GridFsStorage } = require("multer-gridfs-storage")
4require("dotenv").config()
5const MongoClient = require("mongodb").MongoClient
6
7const url = process.env.MONGO_DB_URL
8
9const mongoClient = new MongoClient(url)
10
11// Create a storage object with a given configuration
12const storage = new GridFsStorage({
13 url,
14 file: (req, file) => {
15 //If it is an image, save to photos bucket
16 if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
17 return {
18 bucketName: "photos",
19 filename: `${Date.now()}_${file.originalname}`,
20 }
21 } else {
22 //Otherwise save to default bucket
23 return `${Date.now()}_${file.originalname}`
24 }
25 },
26})
27
28// Set multer storage engine to the newly created object
29const upload = multer({ storage })
30
31const app = express()
32
33app.post("/upload/image", upload.single("avatar"), (req, res) => {
34 const file = req.file
35 // Respond with the file details
36 res.send({
37 message: "Uploaded",
38 id: file.id,
39 name: file.filename,
40 contentType: file.contentType,
41 })
42})
43
44app.get("/images", async (req, res) => {
45 try {
46 await mongoClient.connect()
47
48 const database = mongoClient.db("images")
49 const images = database.collection("photos.files")
50 const cursor = images.find({})
51 const count = await cursor.count()
52 if (count === 0) {
53 return res.status(404).send({
54 message: "Error: No Images found",
55 })
56 }
57
58 const allImages = []
59
60 await cursor.forEach(item => {
61 allImages.push(item)
62 })
63
64 res.send({ files: allImages })
65 } catch (error) {
66 console.log(error)
67 res.status(500).send({
68 message: "Error Something went wrong",
69 error,
70 })
71 }
72})
73
74const server = app.listen(process.env.PORT || 8765, function () {
75 const port = server.address().port
76
77 console.log("App started at port:", port)
78})

If you access http://localhost:8765/images via postman or browser, you should be able to see the list of image details.

list all images

Downloading an image

You can download an image by providing its name using the below code:

index.js
1const express = require("express")
2const multer = require("multer")
3const { GridFsStorage } = require("multer-gridfs-storage")
4require("dotenv").config()
5const MongoClient = require("mongodb").MongoClient
6const GridFSBucket = require("mongodb").GridFSBucket
7
8const url = process.env.MONGO_DB_URL
9
10const mongoClient = new MongoClient(url)
11
12// Create a storage object with a given configuration
13const storage = new GridFsStorage({
14 url,
15 file: (req, file) => {
16 //If it is an image, save to photos bucket
17 if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
18 return {
19 bucketName: "photos",
20 filename: `${Date.now()}_${file.originalname}`,
21 }
22 } else {
23 //Otherwise save to default bucket
24 return `${Date.now()}_${file.originalname}`
25 }
26 },
27})
28
29// Set multer storage engine to the newly created object
30const upload = multer({ storage })
31
32const app = express()
33
34app.post("/upload/image", upload.single("avatar"), (req, res) => {
35 const file = req.file
36 // Respond with the file details
37 res.send({
38 message: "Uploaded",
39 id: file.id,
40 name: file.filename,
41 contentType: file.contentType,
42 })
43})
44
45app.get("/images", async (req, res) => {
46 try {
47 await mongoClient.connect()
48
49 const database = mongoClient.db("images")
50 const images = database.collection("photos.files")
51 const cursor = images.find({})
52 const count = await cursor.count()
53 if (count === 0) {
54 return res.status(404).send({
55 message: "Error: No Images found",
56 })
57 }
58
59 const allImages = []
60
61 await cursor.forEach(item => {
62 allImages.push(item)
63 })
64
65 res.send({ files: allImages })
66 } catch (error) {
67 console.log(error)
68 res.status(500).send({
69 message: "Error Something went wrong",
70 error,
71 })
72 }
73})
74
75app.get("/download/:filename", async (req, res) => {
76 try {
77 await mongoClient.connect()
78
79 const database = mongoClient.db("images")
80
81 const imageBucket = new GridFSBucket(database, {
82 bucketName: "photos",
83 })
84
85 let downloadStream = imageBucket.openDownloadStreamByName(
86 req.params.filename
87 )
88
89 downloadStream.on("data", function (data) {
90 return res.status(200).write(data)
91 })
92
93 downloadStream.on("error", function (data) {
94 return res.status(404).send({ error: "Image not found" })
95 })
96
97 downloadStream.on("end", () => {
98 return res.end()
99 })
100 } catch (error) {
101 console.log(error)
102 res.status(500).send({
103 message: "Error Something went wrong",
104 error,
105 })
106 }
107})
108
109const server = app.listen(process.env.PORT || 8765, function () {
110 const port = server.address().port
111
112 console.log("App started at port:", port)
113})

If you access the URL http://localhost:8765/download/<image_name>, you should be able to see the image.

download image

Source code

You can download the complete source code from here.

Do follow me on twitter where I post developer insights more often!

© 2024 CodingDeft.Com