LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 3518 min read

Mongoose Schemas & Models

Define document structure with a Mongoose Schema, compile it into a Model, and perform CRUD operations through it.

Defining a Schema

A Schema describes a document's shape — its fields, their types, and any constraints — as a plain JavaScript object passed to Mongoose's Schema constructor.

import mongoose from 'mongoose';
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
age: { type: Number, min: 0 },
isActive: { type: Boolean, default: true },
createdAt: { type: Date, default: Date.now },
});

Compiling a Model

A Model is compiled from a Schema, and is the actual interface your application code uses to create, query, update, and delete documents — Mongoose automatically maps a Model's name to a pluralized, lowercased collection name (User → users).

const User = mongoose.model('User', userSchema);

Creating Documents

const user = await User.create({ name: 'Ada Lovelace', email: 'ada@example.com', age: 28 });
console.log(user._id);

Reading, Updating, and Deleting

Mongoose Models expose methods mirroring MongoDB's own operations, but returning richer, schema-aware document instances.

const users = await User.find({ isActive: true });
const user = await User.findById('64f1a2b3c4d5e6f7a8b9c0d1');
await User.updateOne({ email: 'ada@example.com' }, { $set: { age: 29 } });
await User.deleteOne({ email: 'ada@example.com' });
findById Is a Mongoose Convenience

findById() is a Mongoose-specific shorthand for find({ _id: ... }) — one of several ergonomic additions layered on top of the raw driver's API.

Common Beginner Mistakes

Defining the same model twice in different files

Mongoose throws an "OverwriteModelError" if mongoose.model('User', ...) is called more than once — export and import a single shared model instance instead.

Forgetting await on Mongoose's promise-returning methods

Every Mongoose query method returns a Promise — forgetting to await it means your code moves on before the actual database operation completes.

FAQs

Not necessarily — many teams use Mongoose schemas for everyday application-level validation and also add database-level JSON Schema validation as an additional safety net.

Yes — mongoose.connection.db gives you access to the raw MongoDB driver's database object for cases where Mongoose's abstraction doesn't fit.

Summary

A Schema defines document structure, and a Model compiled from it becomes your application's interface for CRUD operations. Next, you'll add validation and middleware hooks to a Mongoose schema.

Next Lesson →

Mongoose Validation & Middleware