Schemas, Models & CRUD
Defining Schemas & Models
const mongoose = require('mongoose');
await mongoose.connect('mongodb://localhost:27017/mydb');
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true }, // real MongoDB
// unique INDEX,
age: Number, // not just an
createdAt: { type: Date, default: Date.now }, // app-level check
}, { timestamps: true }); // auto-adds/maintains createdAt + updatedAt
// virtual — computed, never persisted to the database
userSchema.virtual('isAdult').get(function () {
return this.age >= 18;
});
const User = mongoose.model('User', userSchema); // -> 'users' collectionCRUD Operations
const user = await User.create({ name: 'Alice', email: 'alice@example.com' });
const adults = await User.find({ age: { $gte: 18 } });
const one = await User.findById(user._id);
await User.findByIdAndUpdate(user._id, { age: 31 });
await User.findByIdAndDelete(user._id);
// .lean() — plain JS objects, skips Mongoose document overhead
// (change tracking, virtuals, methods) — good for read-only endpoints
const leanUsers = await User.find({ age: { $gte: 18 } }).lean();
// don't use .lean() if you plan to mutate the result and call .save() on itReferences & populate()
const postSchema = new mongoose.Schema({
title: String,
author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
});
const Post = mongoose.model('Post', postSchema);
// Resolves author's ObjectId into the full User document — a separate
// follow-up query, similar in spirit to a relational JOIN
const posts = await Post.find().populate('author');
console.log(posts[0].author.name);
// Populating across MANY documents can add real N+1-like latency —
// embedding frequently-read, rarely-changed data directly on the
// document is the denormalized alternative for hot read paths.Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free