Complete Lab Steps for the Men's Wear E-Commerce Emporium
Work Flow Steps:
Set up a Mongo Database
Manually CRUD some records
Setup an Express JS Webserver with FORMS and use ROUTES and form data to CRUD the Mongo database.
Do Predicate Joins.
## 1. Set up a new Node.js project
1. Open your terminal and create a new directory:
```bash
mkdir mens-wear-emporium
cd mens-wear-emporium
```
2. Initialize a new Node.js project: —-
```bash
npm init -y
```
2. Install necessary dependencies —-
Install the required packages:
```bash
npm install express mongoose dotenv
npm install --save-dev nodemon
```
3. Create a connection to your MongoDB database —-
1. Create a `.env` file in the root directory:
```bash
touch .env
```
2. Add your MongoDB connection string to the `.env` file: —-
```
MONGODB_URI=your_mongodb_connection_string_here
PORT=3000
```
3. Create a `server.js` file in the root directory:
```bash
touch server.js
```
4. Add the following code to `server.js`:
```javascript
const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(express.json());
// MongoDB Connection
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log('Connected to MongoDB'))
.catch((err) => console.error('Error connecting to MongoDB:', err));
// Routes (we'll add these later)
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
``` done up to here.
## 4. Implement schemas in separate files
1. Create a `models` directory:
```bash
mkdir models
```
2. Create separate files for each schema in the `models` directory:
```bash
touch
models/product.js
models/category.js
models/customer.js
models/order.js
models/review.js **
```
3. Implement each schema in its respective file:
`models/product.js`:
```javascript
const mongoose = require('mongoose');
const productSchema = new mongoose.Schema({
name: { type: String, required: true },
sku: { type: String, required: true, unique: true },
description: String,
price: { type: Number, required: true },
category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
size: [String],
color: [String],
inStock: { type: Boolean, default: true },
images: [String]
}, { timestamps: true });
module.exports = mongoose.model('Product', productSchema);
```
`models/category.js`:
```javascript
const mongoose = require('mongoose');
const categorySchema = new mongoose.Schema({
name: { type: String, required: true },
description: String,
parentCategory: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' }
});
module.exports = mongoose.model('Category', categorySchema);
```
`models/customer.js`:
```javascript
const mongoose = require('mongoose');
const customerSchema = new mongoose.Schema({
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
address: {
street: String,
city: String,
state: String,
zipCode: String,
country: String
}
}, { timestamps: true });
module.exports = mongoose.model('Customer', customerSchema);
```
`models/order.js`:
```javascript
const mongoose = require('mongoose');
const orderSchema = new mongoose.Schema({
customer: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
products: [{
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product' },
quantity: Number,
price: Number
}],
totalAmount: Number,
status: { type: String, enum: ['Pending', 'Shipped', 'Delivered'], default: 'Pending' },
shippingAddress: {
street: String,
city: String,
state: String,
zipCode: String,
country: String
}
}, { timestamps: true });
module.exports = mongoose.model('Order', orderSchema);
```
`models/review.js`:
```javascript
const mongoose = require('mongoose');
const reviewSchema = new mongoose.Schema({
product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
customer: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: true },
rating: { type: Number, required: true, min: 1, max: 5 },
comment: String
}, { timestamps: true });
module.exports = mongoose.model('Review', reviewSchema);
```
5. Create basic CRUD operations for each collection
1. Create a `routes` directory:
```bash
mkdir routes
```
2. Create route files for each model:
```bash
touch
routes/products.js
routes/categories.js
routes/customers.js
routes/orders.js
routes/reviews.js
//done
3. Implement CRUD operations in each route file.
Here's an example for `routes/products.js`:
```javascript
const express = require('express');
const router = express.Router();
const Product = require('../models/product');
// Create a new product
router.post('/', async (req, res) => {
try {
const product = new Product(req.body);
await product.save();
res.status(201).json(product);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
// Get all products
router.get('/', async (req, res) => {
try {
const products = await Product.find();
res.json(products);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
// Get a single product
router.get('/:id', async (req, res) => {
try {
const product = await Product.findById(req.params.id);
if (!product) return res.status(404).json({ message: 'Product not found' });
res.json(product);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
// Update a product
router.patch('/:id', async (req, res) => {
try {
const product = await Product.findByIdAndUpdate(req.params.id, req.body, { new: true });
if (!product) return res.status(404).json({ message: 'Product not found' });
res.json(product);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
// Delete a product
router.delete('/:id', async (req, res) => {
try {
const product = await Product.findByIdAndDelete(req.params.id);
if (!product) return res.status(404).json({ message: 'Product not found' });
res.json({ message: 'Product deleted successfully' });
} catch (error) {
res.status(500).json({ message: error.message });
}
});
module.exports = router;
```
4. Update `server.js` to use the routes:
```javascript
const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();
const productRoutes = require('./routes/products');
const categoryRoutes = require('./routes/categories');
const customerRoutes = require('./routes/customers');
const orderRoutes = require('./routes/orders');
const reviewRoutes = require('./routes/reviews');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(express.json());
// MongoDB Connection
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log('Connected to MongoDB'))
.catch((err) => console.error('Error connecting to MongoDB:', err));
// Routes
app.use('/api/products', productRoutes);
app.use('/api/categories', categoryRoutes);
app.use('/api/customers', customerRoutes);
app.use('/api/orders', orderRoutes);
app.use('/api/reviews', reviewRoutes);
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
```
## 6. Test the database operations
1. Start your server:
```bash
npx nodemon server.js
npx is a package runner tool that comes with npm (Node Package Manager) 5.2+ and higher. It allows you to execute npm package binaries without having to install them globally or locally. Here's a breakdown of the command:
npx: This tool is used to execute packages. nodemon: This is a utility that monitors for any changes in your source code and automatically restarts your server. server.js: This is the main file of your Node.js application that nodemon will run and monitor. When you run npx nodemon server.js, here's what happens:
npx checks if nodemon is installed locally in your project's node_modules folder. If nodemon isn't found locally, npx will temporarily download and cache the latest version of nodemon. npx then runs nodemon server.js. nodemon starts your Node.js application by running server.js. nodemon continues to watch your project files. If it detects any changes in your JavaScript files, it will automatically restart your server. The benefits of using npx nodemon instead of just node server.js are:
You don't need to globally install nodemon. It ensures you're always using the latest version of nodemon. Your server will automatically restart whenever you make changes to your code, which is incredibly helpful during development. This approach is particularly useful in a classroom or learning environment because:
It simplifies the setup process for students. It ensures all students are using the same version of nodemon. It provides a smoother development experience with automatic server restarts.
2. Use a tool like Postman or curl to test your API endpoints. Here are some example requests:
Create a product:
```
POST http://localhost:3000/api/products
Content-Type: application/json
{
"name": "Classic White Shirt",
"sku": "CWS001",
"description": "A timeless white shirt for any occasion",
"price": 49.99,
"size": ["S", "M", "L", "XL"],
"color": ["White"],
"inStock": true
}
```
Get all products:
```
GET http://localhost:3000/api/products
```
Get a single product:
```
GET http://localhost:3000/api/products/:id
```
Update a product:
```
PATCH http://localhost:3000/api/products/:id
Content-Type: application/json
{
"price": 54.99
}
```
Delete a product:
```
DELETE http://localhost:3000/api/products/:id
```
Repeat similar tests for other collections (categories, customers, orders, reviews) to ensure all CRUD operations are working correctly.
This completes the setup of your Men's Wear E-Commerce Emporium project with MongoDB, Express, and Node.js. You now have a functional backend with basic CRUD operations for all your collections.