Share
Explore

JSON Data modelling lab:

megaphone

We'll create detailed schemas and models for the products of the cosmetics warehouse. This will CRUD data records in our database!

Lab guide for designing schemas and models for our cosmetics warehouse using Mongoose.

The guide includes:
Step-by-step instructions for creating each model (Category, Supplier, Product, and Inventory)
Detailed Mongoose schemas with field validations, virtual fields, and middleware
Explanations of key concepts like references, virtuals, and middleware
An updated app.js file that incorporates all the new models
A challenge to create a new product document
Reflection questions to deepen understanding of schema design
Key features:
Use of Mongoose schema options like timestamps and virtuals
Implementation of data validation rules
Use of references to create relationships between models (PREDICATE JOINS)
Pre-save and pre-find middleware for automated slug creation and population
:
Virtual fields for derived data (like subcategories and low stock status)

Lab 2: Bringing Your Data to Life with Mongoose Schemas and Models
## Objective In this lab, you'll create the backbone of our cosmetics warehouse database by designing and implementing Mongoose schemas and models for:
Products
Categories
Suppliers
Inventory.
Here we see that MONGOOSE SCHEMA are like SQL Tables in that they structure the documents / rowsets.

## Prerequisites - Completed Lab 1: Setting up the environment - Node.js and npm installed - MongoDB Atlas connection established

### Step 1: Set Up Your Models Directory
First, let's create a new directory to house our models:
mkdir models cd models ```
Step 2: Create the Category Schema and Model
Let's start with categories. Create a file named `category.js`:
```javascript const mongoose = require('mongoose');
const categorySchema = new mongoose.Schema({ name: { type: String, required: [true, 'A category must have a name'], unique: true, trim: true, maxlength: [40, 'A category name must have less or equal than 40 characters'], minlength: [3, 'A category name must have more or equal than 3 characters'] }, description: { type: String, trim: true }, slug: String, parent: { type: mongoose.Schema.ObjectId, ref: 'Category', default: null } }, { timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } });
// Virtual populate categorySchema.virtual('subcategories', { ref: 'Category', foreignField: 'parent', localField: '_id' });
const Category = mongoose.model('Category', categorySchema);
module.exports = Category; ```

Step 3: Create the Supplier Schema and Model
Now, let's create our suppliers. Create a file named `supplier.js`:
```javascript const mongoose = require('mongoose'); const validator = require('validator');
const supplierSchema = new mongoose.Schema({ name: { type: String, required: [true, 'A supplier must have a name'], trim: true, maxlength: [50, 'A supplier name must have less or equal than 50 characters'] }, email: { type: String, required: [true, 'A supplier must have an email'], unique: true, lowercase: true, validate: [validator.isEmail, 'Please provide a valid email'] }, phone: { type: String, required: [true, 'A supplier must have a phone number'] }, address: { street: String, city: String, state: String, zipCode: String, country: String }, active: { type: Boolean, default: true, select: false } }, { timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } });
const Supplier = mongoose.model('Supplier', supplierSchema);
module.exports = Supplier; ```
Step 4: Create the Product Schema and Model
Time for the star of our show - products! Create a file named `product.js`:
```javascript const mongoose = require('mongoose'); const slugify = require('slugify');
const productSchema = new mongoose.Schema({ name: { type: String, required: [true, 'A product must have a name'], unique: true, trim: true, maxlength: [100, 'A product name must have less or equal than 100 characters'], minlength: [3, 'A product name must have more or equal than 3 characters'] }, slug: String, description: { type: String, required: [true, 'A product must have a description'] }, price: { type: Number, required: [true, 'A product must have a price'] }, category: { type: mongoose.Schema.ObjectId, ref: 'Category', required: [true, 'Product must belong to a category'] }, supplier: { type: mongoose.Schema.ObjectId, ref: 'Supplier', required: [true, 'Product must have a supplier'] }, imageCover: { type: String, required: [true, 'A product must have a cover image'] }, images: [String], createdAt: { type: Date, default: Date.now(), select: false }, sku: { type: String, required: [true, 'A product must have a SKU'], unique: true }, inStock: { type: Boolean, default: true } }, { timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } });
// DOCUMENT MIDDLEWARE: runs before .save() and .create() productSchema.pre('save', function(next) { this.slug = slugify(this.name, { lower: true }); next(); });
// QUERY MIDDLEWARE productSchema.pre(/^find/, function(next) { this.populate({ path: 'category', select: 'name' }).populate({ path: 'supplier', select: 'name' });
next(); });
const Product = mongoose.model('Product', productSchema);
module.exports = Product; ```

Step 5: Create the Inventory Schema and Model

Last but not least, let's manage our inventory. Create a file named `inventory.js`:
```javascript const mongoose = require('mongoose');
const inventorySchema = new mongoose.Schema({ product: { type: mongoose.Schema.ObjectId, ref: 'Product', required: [true, 'Inventory must belong to a product'] }, quantity: { type: Number, required: [true, 'Inventory must have a quantity'], min: [0, 'Quantity cannot be negative'] }, location: { type: String, required: [true, 'Inventory must have a storage location'] }, lastRestocked: { type: Date, default: Date.now() }, lowStockThreshold: { type: Number, default: 10 } }, { timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } });
inventorySchema.virtual('isLowStock').get(function() { return this.quantity <= this.lowStockThreshold; });
inventorySchema.pre(/^find/, function(next) { this.populate({ path: 'product', select: 'name price' });
next(); });
const Inventory = mongoose.model('Inventory', inventorySchema);
module.exports = Inventory; ```

Step 6: Bring It All Together

Now, let's update our `app.js` to include these models:

```javascript const express = require('express'); const mongoose = require('mongoose'); const config = require('./config');
// Import models const Category = require('./models/category'); const Supplier = require('./models/supplier'); const Product = require('./models/product'); const Inventory = require('./models/inventory');
const app = express(); const port = 3000;
mongoose.connect(config.mongoURI, { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log('MongoDB connected... Let\'s build something awesome! 🚀')) .catch(err => console.log(err));
app.get('/', (req, res) => { res.send('Welcome to Cosmetics Warehouse API - Your data is now alive! 💄✨'); });
app.listen(port, () => { console.log(`Server is up and running at http://localhost:${port} - Time to make your database beautiful!`); }); ```
## Awesome Job!
You've just created a robust data structure for our cosmetics warehouse! 🎉 These schemas and models will allow us to:
- Organize products into categories and subcategories - Keep track of our suppliers - Manage product details including price, description, and images - Monitor inventory levels and locations
In the next lab, we'll start building API endpoints to interact with this data. Get ready to bring your warehouse to life!
## Challenge Try to create a new product document and save it to the database. How would you ensure that the referenced category and supplier exist before saving the product?
## Reflection 1. How might this schema design change if we wanted to implement product variants (e.g., different sizes or colors of the same product)? 2. What benefits do the virtual fields (like `subcategories` in Category and `isLowStock` in Inventory) provide? 3. How could we optimize these schemas for faster queries as our database grows?
Keep up the great work! You're well on your way to becoming a MongoDB maestro! 🎵📊
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.