Backend Tutorial MongoDb
Backend Tutorial MongoDb
js,
MongoDB & Mongoose
[Link] 15 | React | Mongoose ODM | MongoDB | Tailwind CSS
1 Install MongoDB
MongoDB stores your products as JSON-like documents on disk. Unlike a JavaScript array, the data survives page
reloads and server restarts.
DO: Go to the MongoDB Community WHY: This is the official page. Always download from here.
1 download page in your browser
Open in browser
[Link]
DO: Select: Version = latest, Platform = WHY: The MSI installer handles everything automatically.
2 Windows, Package = msi — then click
Download
DO: Run the .msi file. When asked, choose WHY: The installer registers MongoDB as a Windows
3 Complete installation and leave all defaults service so it starts automatically.
DO: Add MongoDB to your System PATH: WHY: Adding this lets you type mongosh from any terminal
4 Windows key → Environment Variables → window.
System variables → Path → Edit → New
DO: Click OK on all windows. Close VS WHY: VS Code reads PATH only when it starts. Reopening
5 Code completely, then reopen it. it picks up the change.
DO: Open the VS Code terminal (View → WHY: mongosh connects to your local MongoDB. You
6 Terminal) and run this to confirm MongoDB should see a prompt.
is working
VS Code Terminal
mongosh
DO: Open your browser and go to the WHY: mongosh is the official MongoDB shell. Without it
1 mongosh download page you cannot run mongosh in the VS Code terminal.
Open in browser
[Link]
DO: Select Platform: Windows, Package: msi, WHY: The MSI installer adds mongosh to your PATH
2 then click Download and run the installer automatically so you can use it from any terminal.
DO: Close VS Code completely and reopen it, WHY: VS Code must restart to pick up the new PATH entry
3 then verify mongosh works added by the installer.
VS Code Terminal
mongosh
DO: Run the create-next-app command WHY: This scaffolds the full project structure for you
2 automatically.
VS Code Terminal
npx create-next-app@latest myproduct_mongo
ℹ️ Notice "src/ directory = Yes" — this is why your files live inside src/app/ instead of just app/. All import paths must
account for this.
3 DO: Move into the project folder WHY: All commands from now on run from inside here.
VS Code Terminal
cd myproduct_mongo
4 DO: Open the project in VS Code WHY: This opens myproduct_mongo as your workspace.
VS Code Terminal
code .
myproduct_mongo/
src/
app/
api/
products/ <- you will create this
models/ <- you will create this
[Link]
[Link]
[Link]
DO: Install mongoose in the VS Code WHY: This adds mongoose to your project dependencies.
1 terminal
VS Code Terminal
npm install mongoose
Expected output
added 22 packages, and audited 323 packages in 4s
DO: Open the .env file in the project root and WHY: [Link] reads this file automatically. The
2 add your MongoDB connection string MONGODB_URI variable tells Mongoose where your
database is.
.env
MONGODB_URI=mongodb://localhost:27017/shopdb
DO: Open .gitignore and confirm .env is WHY: [Link] adds this automatically. It stops your
3 listed connection string from being uploaded to GitHub.
DO: Create a folder called lib in the project WHY: Right-click in the VS Code Explorer at the root level
1 root (same level as src/) and choose New Folder. Name it lib.
lib/[Link]
import mongoose from 'mongoose';
if (!cached) {
cached = [Link] = { conn: null, promise: null };
}
if (![Link]) {
[Link] = [Link](MONGODB_URI).then((mongoose) => mongoose);
}
DO: Inside src/app/ create a folder called WHY: Right-click the app/ folder in VS Code Explorer and
1 models choose New Folder. Name it models.
src/app/models/[Link]
// models/[Link]
import mongoose from 'mongoose';
price: { type: Number, Every product must have a price stored as a number (e.g. 12.99).
required: true }
{ timestamps: true } Automatically adds createdAt and updatedAt fields to every document.
[Link] Without this check you get "Cannot overwrite model" errors every time [Link]
|| ... hot-reloads.
[Link]("Product", Registers the model. MongoDB stores documents in a collection called
...) "products".
ℹ️ The import path in your API routes is: import Product from "@/app/models/product" — note lowercase "product".
This matches the filename exactly.
myproduct_mongo/
src/
app/
api/
products/
[Link] <- GET + POST
[id]/
[Link] <- PUT + DELETE
models/
[Link] <- done in Part One
[Link] <- the React UI
lib/
[Link] <- done in Part One
DO: Inside src/app/api/ create a folder called WHY: Right-click src/app/ → New Folder → api. Right-
1 products. Inside products create [Link]. click api → New Folder → products. Right-click products →
New File → [Link].
DO: Type this code into WHY: This file handles two operations: fetching all products
2 src/app/api/products/[Link] (GET) and creating a new one (POST).
src/app/api/products/[Link]
import { NextResponse } from 'next/server';
import { connectDB } from '@/lib/mongodb';
import Product from '@/app/models/product';
Line-by-line explanation
import { connectDB } Imports the shared connection function from lib/[Link]
import Product Imports the Mongoose model — gives you [Link](), [Link](), etc.
await connectDB() Opens (or reuses) the MongoDB connection before running any query
[Link]() Returns every document in the products collection as an array
try / catch in GET If the database is unavailable the route returns a JSON error instead of crashing
[Link]() Reads the JSON body sent by the React form — gives you { title, price }
[Link]({ title, Inserts a new document. MongoDB assigns a unique _id automatically.
price })
{ status: 201 } 201 = Created. Used when a new resource is saved successfully.
DO: Start the dev server and test the GET WHY: npm run dev starts [Link] on port 3000. The browser
3 route in your browser sends a GET request when you visit the URL.
VS Code Terminal
npm run dev
Open in browser
[Link]
DO: Inside [id]/ create [Link] and type this WHY: This handles updating and deleting. The id from the
2 code URL identifies which product to target.
src/app/api/products/[id]/[Link]
import { NextResponse } from 'next/server';
import { connectDB } from '@/lib/mongodb';
import Product from '@/app/models/product';
Line-by-line explanation
{ params } [Link] passes the dynamic URL values here. [Link] is the string from the
URL.
const { id } = await In [Link] 15 params is a Promise — you must await it before destructuring.
params
findByIdAndUpdate(id, Finds the document with that _id and returns the updated version.
..., { new: true })
findByIdAndDelete(id) Permanently removes the document with that _id from the collection.
{ success: true } DELETE responses have no document to return, so we confirm success with a
simple object.
ℹ️ MongoDB _id values are strings like "6650a1b2c3d4e5f6a7b8c9d0". Mongoose accepts them directly — no parseInt()
needed unlike SQL integer IDs.
DO: Open src/app/[Link] — it already exists WHY: Delete everything that was there and type this from
1 from the [Link] scaffold. Replace all its scratch.
content with this code.
function handleEdit(p) {
setEditingId(p._id);
setTitle([Link]);
setPrice([Link]);
useEffect(() => {
fetchProducts();
}, []);
return (
<div className='max-w-xl mx-auto py-16 px-4 font-sans'>
<h1 className='text-2xl font-bold mb-6'>Products</h1>
State variables
The four useState variables and what they store
products The array of product objects fetched from MongoDB. Rendered as the list on
screen.
title The current value of the Product Title input — updated on every keystroke.
price The current value of the Price input — updated on every keystroke.
editingId null when adding. Set to a product _id when Edit is clicked. The form uses this to
decide PUT vs POST.
fetchProducts()
Sends a GET request to /api/products. The route calls connectDB() then [Link]() and returns the full array as
JSON. fetchProducts() stores that array in the products state which triggers a re-render and updates the list on screen.
It is called once when the page loads (via useEffect) and again after every create, update, or delete to keep the list in sync
with the database.
handleSubmit(e)
Called when the form is submitted. [Link]() stops the browser from refreshing the page. It then checks
editingId:
handleEdit(p)
Called when the user clicks Edit on a product. Sets editingId to p._id so handleSubmit knows to use PUT. Sets title and
price to the product's current values so the form fields fill in. The button label changes from 'Add Product' to 'Update
Product' because it reads: {editingId ? 'Update Product' : 'Add Product'}.
handleDelete(id)
Sends DELETE /api/products/{id}. The route calls [Link](id) which permanently removes the
document from MongoDB. fetchProducts() then reloads the list so the deleted item disappears from screen.
[] CREATE — Fill both fields The product appears in the list immediately.
and click Add Product
[] CREATE — Submit with The browser blocks submission. Both fields are required.
empty fields
[] CREATE — Add two or three All products appear as rows with Edit and Delete buttons.
products
[] UPDATE — Click Edit on any Form fills with that product's data. Button says 'Update Product'.
product
[] UPDATE — Change the title The list updates immediately showing the new title.
and click Update
[] DELETE — Click Delete on The product disappears from the list immediately.
any product
mongosh Commands
Run in VS Code terminal
mongosh <- open the MongoDB shell
use shopdb <- switch to your database
[Link]().pretty() <- show all documents
[Link]({ price: { $lt: 20 } }) <- filter by price
[Link]({}) <- clear the entire collection
exit <- close mongosh