How to Upload Image to MongoDB using Only NextJS 13.4?
Last Updated :
03 Jun, 2024
Next.js is a React framework that enables functionality such as server-side rendering and generating static websites. MongoDB is a NoSQL database that stores data in flexible, JSON-like documents. Combining Next.js with MongoDB allows you to build full-stack applications where the backend interacts directly with the database and serves dynamic content to the frontend.
Uploading images to MongoDB using only Next.js 13.4 involves setting up a server-side route to handle the image upload and storing the image in MongoDB. In this article, we will learn how to upload an image to MongoDB using NextJS 13.
Approach to upload Image to MongoDB using only NextJS 13.4
- The project connects to MongoDB using Mongoose and implements GridFS for file storage. It defines a schema for posts with
name
and imageUrl
fields. - The API includes a
POST
endpoint to handle form data, upload images to GridFS, and save posts to MongoDB, as well as a GET
endpoint to fetch all posts. - Another route is provided for fetching and deleting specific images from GridFS and MongoDB. On the frontend,
react-hook-form
is used for form submissions, with FileReader handling image previews. - The
NewPost
component includes a form for inputting post details and uploading images, displaying a preview upon file selection. The Home page renders the NewPost
component.
Step to Create a NextJS App and Installing Module
Step 1: Installation
npx [email protected] my-next-app
cd my-next-app
Step 2: Install the required dependencies:
npm install tailwindcss react-hook-form mongoose mongodb
Project Structure
Project Structure
Step 3: Setting Up MongoDB Connection inside .env file add:
MONGOB_URI = mongodb+srv://yourMongodbnab:[email protected]/DatabaseName
The Updated dependencies of your package.json file will look like this:
"dependencies": {
"autoprefixer": "10.4.19",
"eslint": "9.3.0",
"eslint-config-next": "14.2.3",
"mongodb": "^6.6.2",
"mongoose": "^8.4.0",
"next": "13.4.4",
"postcss": "8.4.38",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-hook-form": "^7.51.5",
"tailwindcss": "^3.4.3"
}
Example: Below is an example of uploading an Image to MongoDB using only NextJS 13.4.
JavaScript
// utils/connectToDb.js
import mongoose from "mongoose";
let client = null;
let bucket = null;
const MONGOB_URI = "mongodb://localhost:27017/myapp";
async function connectToDb() {
if (client) {
return { client, bucket };
}
await mongoose.connect(MONGOB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
client = mongoose.connection;
// use mongoose connection
const db = mongoose.connection;
bucket = new mongoose.mongo.GridFSBucket(db, {
bucketName: "images",
});
console.log("Connected to the Database");
return { client, bucket };
}
export default connectToDb;
JavaScript
// utils/posts.js
import mongoose, { Schema } from "mongoose";
const postsSchema = new Schema({
name: { type: String },
imageUrl: { type: String },
});
module.exports = mongoose.models.Posts || mongoose.model("Posts", postsSchema);
JavaScript
// api/route.jsx
import { NextResponse } from "next/server";
import { Readable } from "stream";
import Posts from "@/utils/posts";
import connectToDb from "@/utils/connectToDb";
export const revalidate = 0;
export const POST = async (req) => {
const { client, bucket } = await connectToDb();
// const newItem = new Posts({ name: "hloe", imageUrl: "image" });
// await newItem.save();
let name;
let image;
const formData = await req.formData();
for (const entries of Array.from(formData.entries())) {
const [key, value] = entries;
if (key == "name") {
name = value;
}
if (typeof value == "object") {
image = Date.now() + value.name;
console.log("done");
const buffer = Buffer.from(await value.arrayBuffer());
const stream = Readable.from(buffer);
const uploadStream = bucket.openUploadStream(image, {});
await stream.pipe(uploadStream);
}
}
const newItem = new Posts({
name,
imageUrl: image,
});
await newItem.save();
return NextResponse.json({ msg: "ok" });
};
export const GET = async () => {
const { client, bucket } = await connectToDb();
const posts = await Posts.find({});
// console.log(await Posts.find({}));
return NextResponse.json(posts);
};
JavaScript
// api/[data]/route.jsx
import connectToDb from "@/utils/connectToDb";
import { NextResponse } from "next/server";
import Posts from "@/utils/posts";
export const revalidate = 0;
export const GET = async (req, { params }) => {
const { client, bucket } = await connectToDb();
const { data } = params;
const files = await bucket
.find({
filename: data,
})
.toArray();
// the resulat is an array and i take the first
//element that i found
const file = files[0];
//reading file using openDownloadStreamByName
const stream = bucket.openDownloadStreamByName(file.filename);
return new NextResponse(stream, {
Headers: { "Content-Type": file.contentType },
});
};
export const DELETE = async (req, { params }) => {
const { client, bucket } = await connectToDb();
try {
const { data } = params;
const deletedPost = await Posts.findByIdAndRemove(data);
const files = await bucket
.find({
filename: deletedPost.imageUrl,
})
.toArray();
// the resulat is an array and i take the first
//element that i found
const file = files[0];
bucket.delete(file._id);
return NextResponse.json({ msg: "ok" });
} catch (e) {
console.log(e);
}
};
JavaScript
// components/newPost.jsx
"use client";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { useForm } from "react-hook-form";
const NewPost = () => {
const { register, handleSubmit, reset } = useForm();
const [previewImage, setPreviewImage] = useState(null);
const router = useRouter();
const [form, setForm] = useState({});
const handleFileChange = (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
setPreviewImage(reader.result);
};
reader.readAsDataURL(file);
} else {
setPreviewImage(null);
}
};
const onSubmit = async (data) => {
let formData = new FormData();
formData.append("name", data.name);
for (let file of data.imageUrl) {
formData.append(file.name, file);
}
await fetch("/api", {
method: "POST",
body: formData,
});
// Clear form data and reset input fields
setForm({});
setPreviewImage(null);
reset();
router.refresh();
};
return (
<main className="flex flex-col items-center justify-between ">
<div className="max-w-md mx-auto">
<form
className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4"
onSubmit={handleSubmit(onSubmit)}
>
<div className="mb-4">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="input1"
>
Text Input 1
</label>
<input
className="shadow appearance-none border rounded w-full
py-2 px-3 text-gray-700 leading-tight focus:outline-none
focus:shadow-outline"
id="input1"
type="text"
placeholder="Enter text input 1"
{...register("name")}
/>
</div>
<div className="mb-4">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="fileInput"
>
File Input
</label>
<input
type="file"
accept="image/*"
className="file-input file-input-bordered w-full max-w-xs"
id="fileInput"
{...register("imageUrl")}
onChange={handleFileChange}
/>
{ previewImage && (
<Image
width={200}
height={200}
src={previewImage}
alt="Preview"
className="mt-2 w-full h-32 object-cover"
/>
)}
</div>
<div className="flex items-center justify-between">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold
py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit"
>
Submit
</button>
</div>
</form>
</div>
</main>
);
};
export default NewPost;
JavaScript
// components/newPost.jsx
"use client";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { useForm } from "react-hook-form";
const NewPost = () => {
const { register, handleSubmit, reset } = useForm();
const [previewImage, setPreviewImage] = useState(null);
const router = useRouter();
const [form, setForm] = useState({});
const handleFileChange = (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
setPreviewImage(reader.result);
};
reader.readAsDataURL(file);
} else {
setPreviewImage(null);
}
};
const onSubmit = async (data) => {
let formData = new FormData();
formData.append("name", data.name);
for (let file of data.imageUrl) {
formData.append(file.name, file);
}
await fetch("/api", {
method: "POST",
body: formData,
});
// Clear form data and reset input fields
setForm({});
setPreviewImage(null);
reset();
router.refresh();
};
return (
<main className="flex flex-col items-center justify-between ">
<div className="max-w-md mx-auto">
<form
className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4"
onSubmit={handleSubmit(onSubmit)}
>
<div className="mb-4">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="input1"
>
Text Input 1
</label>
<input
className="shadow appearance-none border rounded w-full
py-2 px-3 text-gray-700 leading-tight focus:outline-none
focus:shadow-outline"
id="input1"
type="text"
placeholder="Enter text input 1"
{...register("name")}
/>
</div>
<div className="mb-4">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="fileInput"
>
File Input
</label>
<input
type="file"
accept="image/*"
className="file-input file-input-bordered w-full max-w-xs"
id="fileInput"
{...register("imageUrl")}
onChange={handleFileChange}
/>
{previewImage && (
<Image
width={200}
height={200}
src={previewImage}
alt="Preview"
className="mt-2 w-full h-32 object-cover"
/>
)}
</div>
<div className="flex items-center justify-between">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold
py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit"
>
Submit
</button>
</div>
</form>
</div>
</main>
);
};
export default NewPost;
JavaScript
// page.jsx
import NewPost from "./components/newPost";
export default async function Home() {
return (
<div className="">
<div className=" my-20">
<NewPost />
</div>
</div>
);
}
Start your Next.js development server:
npm run dev
Visit http://localhost:3000 in your browser to see the application in action.
Output:
When you enter the file name, upload a file, and then click on the submit button, your file is successfully uploaded to MongoDB.
Conclusion
In conclusion, integrating Next.js with MongoDB allows for the development of full-stack web applications with dynamic content management and storage capabilities. By following the outlined steps, including setting up the MongoDB connection, defining schemas, creating API routes, building UI components, and integrating them into pages, you can efficiently handle tasks like image uploads to MongoDB within a Next.js 13.4 project. This combination enables the creation of robust, scalable, and responsive web applications with server-side rendering and static site generation capabilities, suitable for a wide range of modern web development needs.
Similar Reads
Upload and Retrieve Image on MongoDB using Mongoose
Prerequisites: For getting started with this you should have some familiarity with NodeJS, ExpressJS, MongoDB, and Mongoose.NodeJS: It is a free open-source server environment that uses JavaScript on the server and runs on various platforms (Windows, Linux, Unix, Mac OS X, etc.).It uses asynchronous
4 min read
How to Post Data in MongoDB Using NodeJS?
In this tutorial, we will go through the process of creating a simple Node.js application that allows us to post data to a MongoDB database. Here we will use Express.js for the server framework and Mongoose for interacting with MongoDB. And also we use the Ejs for our front end to render the simple
5 min read
How to Upload Single/Multiple Image to Cloudinary using Node.js ?
Uploading images to Cloudinary from a Node.js application is a common task when you need to manage and store images in the cloud. Cloudinary is a cloud-based service that provides comprehensive solutions for image and video management, including upload, storage, manipulation, and delivery.Approachto
4 min read
How to Upload Image and Preview it Using ReactJS?
In React, uploading and previewing images improve the user experience of the application. It's typical for online apps to provide image upload capability that enables users to choose and upload photographs. We simply upload a photo from our local device to our React Project and preview it using a st
2 min read
How to Handle Errors in MongoDB Operations using NodeJS?
Handling errors in MongoDB operations is important for maintaining the stability and reliability of our Node.js application. Whether we're working with CRUD operations, establishing database connections, or executing complex queries, unexpected errors can arise. Without proper error handling, these
8 min read
How to Upload File using formidable module in Node.js ?
A formidable module is used for parsing form data, especially file uploads. It is easy to use and integrate into your project for handling incoming form data and file uploads.ApproachTo upload file using the formidable module in node we will first install formidable. Then create an HTTP server to ac
2 min read
How to upload files in firebase storage using ReactJS ?
Firebase Storage is a powerful cloud storage solution provided by Google's Firebase platform. It allows developers to store and retrieve user-generated content, such as images, videos, and other files, in a secure and scalable manner. In this article, we will explore how to upload files to Firebase
2 min read
CRUD Operations and File Upload using Node.js and MongoDB
Within the computer programming world, CRUD is an elision for the 4 operations Create, Read, Update, and Delete. Create, Read, Update, and Delete (CRUD) are the four basic functions that models should be able to do, at most. In RESTful applications, CRUD often corresponds to the HTTP methods like  P
15 min read
How To Query For Documents In MongoDB Using NodeJS?
MongoDB is the popular NoSQL database that allows for flexible and scalable data storage. NodeJS and JavaScript runtime built on Chrome's V8 JavaScript engine. It is often used with MongoDB to build powerful and efficient applications. In this article, we will guide you on how to query the documents
4 min read
How to test file uploads in Postman using Express?
In web development, handling file uploads is a major requirement for various APIs. Postman is a powerful tool used for API testing, facilitates the process of testing file uploads. In this article we will see how we can test file upload with the help of Postman. Prerequisites:Node and NPM/Yarn insta
3 min read