MongoDB Connection & Schemas — Mongoose Setup
Mongoose is a MongoDB ODM (Object Document Mapper) that makes it easy to connect, model, and validate data in Node.js.
Mongoose is an ODM (Object Document Mapper) for MongoDB and Node.js. Think of it as a translator between your Express app and MongoDB — it helps you:
- Connect — Establish a connection to MongoDB (local or Atlas cloud)
- Define schemas — Describe what your data looks like (what fields, what types)
- Validate — Automatically validate data before saving to the database
- Query — Use simple JavaScript methods to CRUD data
- Middleware — Run functions before/after saving (like hashing passwords)
Remember in the Express chapter (2.1-2.5), we stored biryani data in in-memory arrays? When the server restarted, all orders were lost. Mongoose + MongoDB fixes that — data persists in the cloud, just like Swiggy's real order database.
Installing Mongoose:
npm install mongoose
That's it. One command and Mongoose is ready to use. Now let's connect to a MongoDB database.
MongoDB Atlas is MongoDB's cloud database service. It offers a free tier (512MB storage) that's perfect for learning. Instead of running MongoDB on your laptop, Atlas hosts it in the cloud — just like Swiggy doesn't run its database on a single laptop but on cloud servers.
Step 1: Create a free Atlas account
Go to mongodb.com/atlas and sign up for a free account. Create a cluster (M0 free tier) and get your connection string.
Step 2: Get your connection string
Your connection string looks like this:
mongodb+srv://username:password@cluster0.abcde.mongodb.net/swiggy-db?retryWrites=true&w=majority
Step 3: Connect using Mongoose
// db.js — MongoDB Connection
import mongoose from 'mongoose';
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI);
console.log('MongoDB connected: ' + conn.connection.host);
} catch (error) {
console.error('Connection failed: ' + error.message);
process.exit(1);
}
};
export default connectDB;
Step 4: Call the connection in server.js
// server.js — Connect to MongoDB on startup
import express from 'express';
import connectDB from './config/db.js';
const app = express();
// Connect to MongoDB before starting the server
connectDB();
// Middleware
app.use(express.json());
// Routes
app.get('/', (req, res) => {
res.json({ message: 'Swiggy Backend — MongoDB Connected!' });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log('Server running on port ' + PORT);
});
Connection events you should know:
mongoose.connection.on('connected')— Fires when connected successfullymongoose.connection.on('error')— Fires on connection errormongoose.connection.on('disconnected')— Fires when connection is lost
Pro tip: Always add connection error handling. If MongoDB goes down, your API should respond gracefully instead of crashing.
A Schema in Mongoose defines the structure of your documents — what fields they have, what data types, and what validation rules apply. Think of it as a blueprint for your data.
Creating a Biryani Order Schema:
// models/Biryani.js — Biryani Order Schema
import mongoose from 'mongoose';
const biryaniSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Biryani ka naam to batao bhai!'],
trim: true,
minlength: [3, 'Itna chota naam? Kya biryani hai yeh?']
},
restaurant: {
type: String,
required: [true, 'Kaunsa restaurant ka biryani hai?'],
trim: true
},
price: {
type: Number,
required: [true, 'Price to batao — free mein thodi degi Swiggy?'],
min: [1, 'Itna sasta biryani? Kahan milta hai?']
},
category: {
type: String,
enum: ['Chicken', 'Mutton', 'Veg', 'Fish', 'Beef'],
default: 'Chicken'
},
spicyLevel: {
type: String,
enum: ['Low', 'Medium', 'High', 'Extra High'],
default: 'Medium'
},
isAvailable: {
type: Boolean,
default: true
},
description: {
type: String,
maxlength: [500, 'Itna bada description? Essay nahi likhna bhai!'],
default: ''
},
rating: {
type: Number,
min: 0,
max: 5,
default: 3.5
},
ingredients: [{
name: String,
quantity: String
}]
}, {
timestamps: true // Automatically adds createdAt and updatedAt
});
Schema Types in Mongoose:
| Type | Description | Example |
|---|---|---|
| String | Text data | 'Chicken Biryani' |
| Number | Numeric values | 250 |
| Boolean | true/false | true |
| Date | Date/timestamp | new Date() |
| Array | List of items | ['rice', 'chicken'] |
| ObjectId | Reference to another document | mongoose.Types.ObjectId |
| Mixed | Any data type | { anyField: 'anything' } |
A Model is a compiled version of your Schema. It gives you methods to actually query, create, update, and delete documents in MongoDB. If the Schema is the blueprint, the Model is the factory that produces objects from that blueprint.
// models/Biryani.js — Full Schema + Model
import mongoose from 'mongoose';
const biryaniSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true },
restaurant: { type: String, required: true },
price: { type: Number, required: true, min: 1 },
category: {
type: String,
enum: ['Chicken', 'Mutton', 'Veg', 'Fish'],
default: 'Chicken'
},
isAvailable: { type: Boolean, default: true },
rating: { type: Number, default: 3.5 }
}, { timestamps: true });
// Create the Model from the Schema
const Biryani = mongoose.model('Biryani', biryaniSchema);
export default Biryani;
Using the Model in your routes:
// routes/biryani.routes.js
import express from 'express';
import Biryani from '../models/Biryani.js';
const router = express.Router();
// Create a new biryani
router.post('/', async (req, res) => {
try {
const biryani = await Biryani.create(req.body);
res.status(201).json({ success: true, data: biryani });
} catch (error) {
res.status(400).json({ success: false, message: error.message });
}
});
// Get all biryanis
router.get('/', async (req, res) => {
try {
const biryanis = await Biryani.find({});
res.json({ success: true, count: biryanis.length, data: biryanis });
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
});
export default router;
Important: Mongoose automatically pluralizes and lowercases your model name to create the MongoDB collection. mongoose.model('Biryani', biryaniSchema) creates a collection called biryanis.
The first argument to mongoose.model() is the singular name (e.g., 'Biryani'). The collection name becomes 'biryanis' (plural, lowercase). You can override this with the collection option in the schema.
Hardcoding your MongoDB connection string in your code is like writing your Swiggy password on a napkin and leaving it on the restaurant counter. Never hardcode secrets!
Step 1: Create a .env file
# .env — Environment Variables
MONGO_URI=mongodb+srv://username:password@cluster0.abcde.mongodb.net/swiggy-db?retryWrites=true&w=majority
PORT=3000
NODE_ENV=development
Step 2: Install dotenv
npm install dotenv
Step 3: Load .env in your app
// server.js — With Environment Variables
import 'dotenv/config';
import express from 'express';
import connectDB from './config/db.js';
const app = express();
// Connect to MongoDB using URI from .env
connectDB();
app.use(express.json());
app.listen(process.env.PORT || 3000, () => {
console.log('Server running in ' + process.env.NODE_ENV + ' mode on port ' + process.env.PORT);
});
Step 4: Update db.js to use .env
// config/db.js — Using MONGO_URI from environment
import mongoose from 'mongoose';
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI);
console.log('MongoDB Connected: ' + conn.connection.host);
} catch (error) {
console.error('Error: ' + error.message);
process.exit(1);
}
};
export default connectDB;
Why .env matters:
- Security — Your database credentials stay out of your code repository
- Portability — Different environments (dev, staging, production) use different .env files
- Configurability — Change database, port, or settings without touching code
- Team safety — Add .env to .gitignore so no one accidentally commits it
Pro tip: Create a .env.example file in your repo with placeholder values so new developers know what variables they need to set.
Key Takeaways
- ✅ Mongoose is an ODM (Object Document Mapper) that connects Express to MongoDB
- ✅ mongoose.connect() connects to MongoDB Atlas using a connection string from .env
- ✅ Schema defines document structure: field names, types, validation rules, defaults
- ✅ Model is the compiled schema — use it to query/create/update/delete documents
- ✅ mongoose.model("Biryani") creates a collection called "biryanis" (plural, lowercase)
- ✅ Always use .env for MONGO_URI — never hardcode database credentials
- ✅ Add timestamps: true to get createdAt and updatedAt automatically
- ✅ Schema validation (required, min, enum, etc.) catches bad data before it reaches the DB
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login