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
How to Store Images in MongoDB using NodeJS?
We will create a simple web application that allows users to upload images, store them directly in MongoDB as buffers, and display them on a webpage. We will use Node.js, Express, MongoDB, and Multer to achieve this. By the end of this tutorial, you will have a working image upload application. Prer
3 min read
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 asynchronou
5 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. Approacht
5 min read
How to Update a Document in MongoDB using NodeJS?
Updating documents in MongoDB is a basic operation for maintaining and managing your database effectively. Node.js, combined with MongoDB, offers a powerful and flexible environment for performing database operations. In this article we will learn how to update a document from a MongoDB collection,
4 min read
How to Upload Image and Preview it Using ReactJS?
In React upload and preview 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 static me
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 a
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
How to Retrieve Data from MongoDB Using NodeJS?
MongoDB, the most popular NoSQL database, is an open-source document-oriented database. The term âNoSQLâ means ânon-relationalâ. It means that MongoDB isnât based on the table-like relational database structure but provides an altogether different mechanism for the storage and retrieval of data. Thi
3 min read