Ever noticed how online stores sell EVERYTHING? T-shirts have sizes and colors, eBooks have formats and page counts, online courses have modules and duration. How do they store such wildly different products in one database?
Your challenge: Build a flexible product catalog that can handle ANY type of product without changing your database structure!
A MongoDB-powered product catalog for "MegaMart" - an online store that sells:
No rigid tables. No schema migrations. Just flexible documents that adapt to any product!
// MongoDB Playground Setup
// Copy this to MongoDB Playground or your local MongoDB
// Create our catalog database
use megamart_catalog
// Sample products to get you started
db.products.insertMany([
{
name: "Coding Ninja T-Shirt",
category: "clothing",
price: 24.99,
sizes: ["S", "M", "L", "XL"],
colors: ["black", "navy", "gray"],
material: "100% cotton",
inStock: true
},
{
name: "JavaScript Mastery eBook",
category: "digital",
price: 39.99,
format: "PDF",
pages: 450,
fileSize: "15MB",
downloadLink: "https://download.example.com/js-mastery"
}
])
print("✅ MegaMart catalog initialized!")
Let's see why traditional SQL struggles with diverse products:
-- In SQL, you'd need separate tables or tons of NULL columns
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(255),
price DECIMAL(10,2),
-- Clothing fields
size VARCHAR(10),
color VARCHAR(50),
material VARCHAR(100),
-- Digital fields
format VARCHAR(20),
file_size VARCHAR(20),
download_link VARCHAR(500),
-- Course fields
duration_hours INT,
modules INT,
instructor VARCHAR(255)
-- 😱 Most fields are NULL for each product type!
);
The MongoDB Way - Embrace Flexibility!
// Each product has ONLY the fields it needs
db.products.insertOne({
name: "MongoDB Masterclass",
category: "course",
price: 89.99,
instructor: "Sarah Chen",
duration: "8 hours",
modules: [
{ title: "NoSQL Basics", duration: "45 min" },
{ title: "Document Design", duration: "60 min" },
{ title: "Aggregation Pipeline", duration: "90 min" }
],
skillLevel: "intermediate",
certificateIncluded: true
})
print("✨ No schema changes needed - just add what makes sense!")
Let's add more diverse products and see MongoDB shine:
// Add a video game with nested reviews
db.products.insertOne({
name: "Space Invaders 3000",
category: "game",
price: 59.99,
platforms: ["PC", "PS5", "Xbox"],
genres: ["Action", "Sci-Fi"],
rating: "T for Teen",
systemRequirements: {
minimum: {
ram: "8GB",
storage: "50GB",
graphics: "GTX 1060"
},
recommended: {
ram: "16GB",
storage: "100GB",
graphics: "RTX 3070"
}
},
reviews: [
{ user: "GamerPro", rating: 5, comment: "Best game ever!" },
{ user: "CasualPlayer", rating: 4, comment: "Fun but challenging" }
]
})
// Add a bundled product (clothing with accessories)
db.products.insertOne({
name: "Developer Starter Pack",
category: "bundle",
price: 99.99,
items: [
{
type: "clothing",
name: "Code & Coffee Hoodie",
sizes: ["M", "L", "XL"]
},
{
type: "accessory",
name: "Rubber Duck Debugger",
quantity: 1
},
{
type: "digital",
name: "IDE Theme Pack",
formats: ["VSCode", "IntelliJ"]
}
],
savings: "Save $20 vs buying separately!"
})
print("🎉 Products added with completely different structures!")
Now let's query our flexible catalog:
// Find all products under $50
db.products.find({ price: { $lt: 50 } })
// Find clothing in specific sizes
db.products.find({
category: "clothing",
sizes: { $in: ["L", "XL"] }
})
// Find digital products with instant download
db.products.find({
category: "digital",
downloadLink: { $exists: true }
})
// Complex query: Find games for PC with good reviews
db.products.find({
category: "game",
platforms: "PC",
"reviews.rating": { $gte: 4 }
})
// Search within nested documents
db.products.find({
"items.type": "digital"
})
// Text search across all fields
db.products.createIndex({ "$**": "text" })
db.products.find({ $text: { $search: "JavaScript" } })
Let's build some powerful analytics:
// Average price by category
db.products.aggregate([
{
$group: {
_id: "$category",
avgPrice: { $avg: "$price" },
count: { $sum: 1 }
}
},
{ $sort: { avgPrice: -1 } }
])
// Most popular clothing sizes
db.products.aggregate([
{ $match: { category: "clothing" } },
{ $unwind: "$sizes" },
{
$group: {
_id: "$sizes",
products: { $sum: 1 }
}
},
{ $sort: { products: -1 } }
])
// Bundle savings calculator
db.products.aggregate([
{ $match: { category: "bundle" } },
{ $unwind: "$items" },
{
$group: {
_id: "$name",
totalItems: { $sum: 1 },
itemTypes: { $addToSet: "$items.type" }
}
}
])
// Review insights
db.products.aggregate([
{ $match: { reviews: { $exists: true } } },
{ $unwind: "$reviews" },
{
$group: {
_id: "$name",
avgRating: { $avg: "$reviews.rating" },
reviewCount: { $sum: 1 }
}
},
{ $match: { avgRating: { $gte: 4 } } },
{ $sort: { avgRating: -1 } }
])
// Add inventory tracking that works for physical AND digital products
// Hint: Physical products have quantity, digital have licenses
// Your code here:
// Build a query to find "similar products"
// - Same category
// - Similar price range (±20%)
// - At least one matching attribute
// Your code here:
// Create a system for time-limited discounts
// - Add discount info without modifying product structure
// - Query active sales
// - Calculate final prices
// Your code here:
Online Store Project
Health Tracker App
Book Lending System
// Insert
db.collection.insertOne({})
db.collection.insertMany([])
// Find
db.collection.find({ field: value })
db.collection.findOne({ field: value })
// Query Operators
{ field: { $gt: value } } // Greater than
{ field: { $in: [array] } } // In array
{ field: { $exists: true } } // Field exists
{ $or: [{}, {}] } // OR condition
// Update
db.collection.updateOne(
{ filter },
{ $set: { field: value } }
)
// Aggregation
db.collection.aggregate([
{ $match: {} }, // Filter
{ $group: {} }, // Group
{ $sort: {} }, // Sort
{ $unwind: "" } // Expand arrays
])