0% found this document useful (0 votes)
2 views19 pages

Backend Tutorial MongoDb

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views19 pages

Backend Tutorial MongoDb

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Full-Stack Development with Next.

js,
MongoDB & Mongoose
[Link] 15 | React | Mongoose ODM | MongoDB | Tailwind CSS

About This Tutorial


This tutorial teaches you to build a full-stack product management app step by step. You will start from an empty
folder and finish with a working [Link] application that stores data permanently in MongoDB. Every file shown is
the exact code from the finished project — nothing is left out.

PART ONE PART TWO


Setup & Configuration Full CRUD Application
Install MongoDB, scaffold [Link], install Mongoose, Build every API route and the complete React page —
connect the database, define the Product model, and add, display, edit, and delete products — all saved
verify everything is working. permanently in MongoDB.

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


PART ONE
Setup & Configuration
Install → Scaffold → Connect → Model → Verify

✓ What you will have by the end of Part One


— MongoDB installed and running on your computer
— A [Link] 15 project called myproduct_mongo open in VS Code
— Mongoose installed and the .env connection string configured
— lib/[Link] — the shared database connection used by every route
— src/app/models/[Link] — the Product schema
— A working GET /api/products endpoint returning JSON

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

Add to System PATH


C:\Program Files\MongoDB\Server\8.0\bin

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

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


Expected output — you should see something like this
Current Mongosh Log ID: ...
Connecting to: mongodb://[Link]:27017/
Using MongoDB: 8.0.x
test>

Type this to exit mongosh


exit

⚠ If mongosh is not recognised


Close VS Code and reopen it — it must restart to read the updated PATH.
Check that C:\Program Files\MongoDB\Server\8.0\bin exists.
Repeat step 4 if the folder was not in the list.

1B Install MongoDB Shell (mongosh)


mongosh is the command-line tool you use to connect to MongoDB, inspect your data, and verify that your API routes
are saving documents correctly. The MongoDB installer does not always include it, so install it separately.

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

Expected output — you should see a prompt like this


Current Mongosh Log ID: ...
Connecting to: mongodb://[Link]:27017/
test>

2 Create the [Link] Project


[Link] handles both the frontend (what users see) and the backend API routes that talk to MongoDB — all in one
project.

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


DO: Open VS Code. Open the folder where WHY: View → Terminal. Make sure you are in the right
1 you want to create the project. Open the parent folder first.
terminal.

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

Answer the questions exactly like this:

QUESTION YOUR ANSWER

Would you like to use TypeScript? No

Would you like to use ESLint? Yes

Would you like to use Tailwind CSS? Yes

Would you like your code inside a src/ directory? Yes

Would you like to use App Router? Yes

Would you like to use Turbopack? No

Would you like to customize the import alias? No

ℹ️ 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 .

After setup your project structure looks like this:

myproduct_mongo/
src/
app/
api/
products/ <- you will create this
models/ <- you will create this
[Link]
[Link]
[Link]

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


lib/ <- you will create this
.env
.gitignore

3 Install Mongoose and Configure the Environment


Mongoose is the ODM (Object Document Mapper) that lets your JavaScript code talk to MongoDB. You describe your
data in a Schema and Mongoose handles all the database operations.

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

What each part means


mongodb:// the protocol — tells Mongoose this is a MongoDB connection
localhost MongoDB is running on your own computer
27017 the default MongoDB port — never changes locally
shopdb the database name — MongoDB creates it automatically on first use

DO: Open .gitignore and confirm .env is WHY: [Link] adds this automatically. It stops your
3 listed connection string from being uploaded to GitHub.

.gitignore — these lines should already be present


.env
.[Link]

4 Create the Database Connection — lib/[Link]


Every API route needs a database connection. Instead of each route opening its own connection (which would be slow
and cause errors), you create one shared connection file that all routes import.

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.

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


DO: Inside lib, create a file called [Link] WHY: This is the exact connection file used in the project.
2 and type this code

lib/[Link]
import mongoose from 'mongoose';

const MONGODB_URI = [Link].MONGODB_URI;

let cached = [Link];

if (!cached) {
cached = [Link] = { conn: null, promise: null };
}

export async function connectDB() {


if ([Link]) return [Link];

if (![Link]) {
[Link] = [Link](MONGODB_URI).then((mongoose) => mongoose);
}

[Link] = await [Link];


return [Link];
}

How this file works — read before moving on


[Link] A global cache shared across all API calls in the same Node process
[Link] If a connection already exists, return it immediately — no new connection needed
[Link] If a connection is being established, wait for it — prevents opening two at once
[Link]() Opens the actual connection to MongoDB using the URI from .env
connectDB() The function your API routes will import and call at the top of each handler

⚠ Important — the import alias


Your routes import this file with: import { connectDB } from "@/lib/mongodb"
The @/ alias maps to your src/ folder in [Link] when using the src/ directory option.
So @/lib/mongodb resolves to src/../lib/mongodb — i.e. the lib folder at the project root.

5 Create the Product Model — src/app/models/[Link]


A Mongoose model defines the shape of documents in your MongoDB collection. It is the equivalent of a table definition
in a SQL database.

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.

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


DO: Inside models/, create a file called WHY: This is the exact model file used in the project.
2 [Link] and type this code

src/app/models/[Link]
// models/[Link]
import mongoose from 'mongoose';

const ProductSchema = new [Link]({


title: { type: String, required: true },
price: { type: Number, required: true },
}, { timestamps: true });

// Prevent model re-registration in [Link] dev mode


const Product = [Link]
|| [Link]('Product', ProductSchema);

export default Product;

What each part of the schema means


title: { type: String, Every product must have a title. Mongoose rejects documents without it.
required: true }

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 — MongoDB + Mongoose + [Link] Tutorial


PART TWO
Full CRUD Application
API Routes → React Page → Test Every Feature

✓ What you will build in Part Two


— GET /api/products — fetch all products from MongoDB
— POST /api/products — save a new product from the form
— PUT /api/products/[id] — update an existing product
— DELETE /api/products/[id] — remove a product
— src/app/[Link] — the complete React UI with form + product list

Here is every file you will create in Part Two:

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

6 Create the Products API — GET and POST


In [Link] App Router, a file called [Link] inside app/api/products/ automatically becomes the endpoint /api/products.
You export one function per HTTP method.

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';

export async function GET() {


try {
await connectDB();

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


const products = await [Link]();
return [Link](products);
} catch (err) {
return [Link]({ error: [Link] }, { status: 500 });
}
}

export async function POST(request) {


await connectDB();
const { title, price } = await [Link]();
const product = await [Link]({ title, price });
return [Link](product, { status: 201 });
}

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]

Expected browser output — empty array because no products yet


[]

📷 Screenshot of browser showing [] at /api/products


[ Paste your screenshot here ]

7 Create the Dynamic Route — PUT and DELETE


To update or delete a specific product you need its _id in the URL. [Link] captures that with a dynamic segment folder
named [id].

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


DO: Inside src/app/api/products/ create a WHY: The square brackets are required. They tell [Link]
1 folder called [id] — including the square this is a dynamic segment that captures whatever is in the
brackets URL at that position.

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';

export async function PUT(request, { params }) {


await connectDB();
const { id } = await params;
const { title, price } = await [Link]();
const product = await [Link](
id,
{ title, price },
{ new: true }
);
return [Link](product);
}

export async function DELETE(request, { params }) {


await connectDB();
const { id } = await params;
await [Link](id);
return [Link]({ success: true });
}

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.

8 Build the React Page — src/app/[Link]

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


The [Link] file is the entire UI. It holds all state, all API calls, and renders the form and the product list. There are no
separate component files — everything lives in one place.

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.

src/app/[Link] — replace the full file content


'use client';

import { useState, useEffect } from 'react';

export default function Home() {


const [products, setProducts] = useState([]);
const [title, setTitle] = useState('');
const [price, setPrice] = useState('');
const [editingId, setEditingId] = useState(null);

async function fetchProducts() {


const res = await fetch('/api/products');
if (![Link]) return;
const data = await [Link]();
setProducts(data);
}

async function handleSubmit(e) {


[Link]();
if (editingId) {
await fetch(`/api/products/${editingId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ title, price: Number(price) }),
});
setEditingId(null);
} else {
await fetch('/api/products', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ title, price: Number(price) }),
});
}
setTitle('');
setPrice('');
fetchProducts();
}

function handleEdit(p) {
setEditingId(p._id);
setTitle([Link]);
setPrice([Link]);

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


}

async function handleDelete(id) {


await fetch(`/api/products/${id}`, { method: 'DELETE' });
fetchProducts();
}

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>

<form onSubmit={handleSubmit} className='flex flex-col gap-3 mb-8'>


<input type='text' placeholder='Product title'
value={title} onChange={(e) => setTitle([Link])}
required className='border rounded px-3 py-2' />
<input type='number' placeholder='Price'
value={price} onChange={(e) => setPrice([Link])}
required className='border rounded px-3 py-2' />
<button type='submit'
className='bg-black text-white rounded px-4 py-2 hover:bg-zinc-700'>
{editingId ? 'Update Product' : 'Add Product'}
</button>
</form>

<ul className='flex flex-col gap-3'>


{[Link]((p) => (
<li key={p._id}
className='border rounded px-4 py-3 flex items-center justify-between'>
<div>
<span className='font-medium'>{[Link]}</span>
<span className='ml-4 text-zinc-500'>${[Link]}</span>
</div>
<div className='flex gap-2'>
<button onClick={() => handleEdit(p)}
className='text-blue-600'>Edit</button>
<button onClick={() => handleDelete(p._id)}
className='text-red-600'>Delete</button>
</div>
</li>
))}
</ul>
</div>
);
}

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


9 How Every Function Works

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:

Two code paths inside handleSubmit


editingId is set Sends PUT /api/products/{editingId} with the new title and price. Clears editingId
so the form returns to Add mode.
editingId is null Sends POST /api/products with title and price. MongoDB assigns a new _id
automatically.
In both cases: title and price fields are cleared, then fetchProducts() reloads the list.

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.

Edit flow — step by step


Full edit journey from click to saved
1. User clicks Edit handleEdit(p) is called with the full product object
2. editingId = p._id The form now knows which product is being edited
3. Fields fill in setTitle([Link]) and setPrice([Link]) update the inputs
4. Button changes label 'Add Product' becomes 'Update Product'

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


5. User changes values Each keystroke calls setTitle / setPrice updating state
6. User clicks Update handleSubmit fires; editingId is set so it calls PUT
Product

7. PUT /api/products/_id Mongoose runs findByIdAndUpdate — document saved in MongoDB


8. setEditingId(null) Form returns to Add mode; fields clear; list reloads

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


10 Test Every Feature
Make sure npm run dev is still running, then open: [Link]

[] READ — Page loads The page opens. No errors in the console.

[] 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

Verify data is actually saved in MongoDB


VS Code Terminal — open a second tab
mongosh
use shopdb
[Link]().pretty()
exit

Expected mongosh output after adding products


[
{
_id: ObjectId('...'),
title: 'Wireless Earbuds',
price: 12.99,
createdAt: ISODate('...'),
updatedAt: ISODate('...')
},
...
]

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


✓ Tutorial Complete!

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


— MongoDB running locally with a shopdb database
— lib/[Link] — shared connection with global caching
— src/app/models/[Link] — Mongoose schema with timestamps
— GET /api/products — returns all products from MongoDB
— POST /api/products — creates a new product and returns it
— PUT /api/products/[id] — updates a product by _id
— DELETE /api/products/[id] — removes a product by _id
— src/app/[Link] — React UI with create, edit, and delete

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


QUICK REFERENCE
Copy These When You Need Them
Commands | fetch() patterns | Mongoose methods

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

fetch() Patterns Used in This Project


[Link] fetch calls
// READ — get all products
const res = await fetch('/api/products');
const data = await [Link](); // data is the array

// CREATE — add a new product


await fetch('/api/products', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ title, price: Number(price) }),
});

// UPDATE — save changes to an existing product


await fetch(`/api/products/${editingId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ title, price: Number(price) }),
});

// DELETE — remove a product


await fetch(`/api/products/${id}`, { method: 'DELETE' });

Mongoose Methods Used in This Project


API route queries
await connectDB(); // always call this first

// GET — fetch all


const products = await [Link]();

// POST — create one


const product = await [Link]({ title, price });

// PUT — update by _id, return updated document

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial


const updated = await [Link](
id,
{ title, price },
{ new: true }
);

// DELETE — remove by _id


await [Link](id);

React Hooks Used in This Project


useState and useEffect patterns
// useState — remember a value between renders
const [products, setProducts] = useState([]); // starts as empty array
const [title, setTitle] = useState(''); // starts as empty string
const [editingId, setEditingId] = useState(null); // starts as null

// useEffect — run code once when the page first loads


useEffect(() => {
fetchProducts();
}, []); // empty [] = run once only

// Controlled input pattern — React owns the field value


value={title}
onChange={(e) => setTitle([Link])}
// Every keystroke calls setTitle → state updates → field re-renders

Final Project File Structure


myproduct_mongo/
src/
app/
api/
products/
[Link] <- GET + POST
[id]/
[Link] <- PUT + DELETE
models/
[Link] <- Mongoose schema
[Link]
[Link]
[Link] <- React UI
lib/
[Link] <- shared DB connection
.env <- MONGODB_URI
.gitignore
[Link]
[Link]

myproduct_mongo — MongoDB + Mongoose + [Link] Tutorial

You might also like