Definitions, categories, and practical examples of Model methods and related Mongoose features. Focus: MongoDB via Mongoose (Node.js).
A Schema defines the structure, types, validators, defaults and indexes for documents in a MongoDB collection.
// user.schema.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true, lowercase: true },
age: { type: Number, min: 0 },
createdAt: { type: Date, default: Date.now }
});
module.exports = userSchema;
String, Number, Date, Boolean, Buffer, ObjectId, Array, Mixedrequired, min, max, match, enumdefaultschema.index({ field: 1 })A Model is created from a Schema and provides the API to interact with a MongoDB collection (CRUD, queries, aggregation, transactions, etc.).
const mongoose = require('mongoose');
const userSchema = require('./user.schema');
const User = mongoose.model('User', userSchema); // creates 'users' collection (pluralized)
new User({...})User.find()| Method | Purpose |
|---|---|
| Model.create(docs) | Create & save one or many documents |
| new Model(doc).save() | Instantiate document & save (runs setters, validation) |
| Model.insertMany(docs) | Bulk insert many documents (fast) |
// create single
const user = await User.create({ name:'A', email:'a@x.com' });
// insert many
await User.insertMany([{name:'B', email:'b@x.com'}, {name:'C', email:'c@x.com'}]);
// new + save
const u = new User({name:'D'}); await u.save();
| Method | Purpose |
|---|---|
| Model.find(filter) | Return array of docs |
| Model.findOne(filter) | Return first matching doc |
| Model.findById(id) | Find document by _id |
| Model.exists(filter) | Boolean if any doc matches |
| Model.countDocuments(filter) | Accurate count of matching docs |
| Model.distinct(field, filter) | Unique field values |
// find all users older than 18
const adults = await User.find({ age: { $gte: 18 } }).sort({name:1}).limit(50);
// find one
const u = await User.findOne({ email: 'a@x.com' });
// find by id
const single = await User.findById('64f...');
| Method | Purpose / notes |
|---|---|
| Model.updateOne(filter, update) | Update first match (no doc returned) |
| Model.updateMany(filter, update) | Update multiple docs |
| Model.findOneAndUpdate(filter, update, opts) | Find & update (can return new doc) |
| Model.findByIdAndUpdate(id, update, opts) | Update by id (shorthand) |
| Document.save() | Modify document fields then save (runs validation) |
// updateOne
await User.updateOne({ email:'a@x.com' }, { $set: { age: 30 } });
// findOneAndUpdate - return updated doc
const updated = await User.findOneAndUpdate(
{ email:'a@x.com' },
{ $inc: { visits: 1 } },
{ new: true } // returns the NEW doc
);
// instance save
const doc = await User.findById(id); doc.name = 'New'; await doc.save();
| Method | Notes |
|---|---|
| Model.deleteOne(filter) | Delete first match |
| Model.deleteMany(filter) | Delete multiple docs |
| Model.findOneAndDelete(filter) | Find & delete, returns deleted doc |
| Model.findByIdAndDelete(id) | Delete by id |
// delete single
await User.deleteOne({ email: 'x@x.com' });
// delete many (careful)
await User.deleteMany({ inactive: true });
// find and delete
const removed = await User.findByIdAndDelete(id);
Model.aggregate().// group by month, count users
const pipeline = [
{ $match: { createdAt: { $gte: new Date('2024-01-01') } } },
{ $project: { month: { $month: '$createdAt' } } },
{ $group: { _id: '$month', count: { $sum: 1 } } }
];
const stats = await User.aggregate(pipeline);
Model.bulkWrite().
await User.bulkWrite([
{ insertOne: { document: { name:'A', email:'a@x.com' } } },
{ updateOne: { filter: { email:'b@x' }, update: { $set:{active:true} } } },
{ deleteOne: { filter: { old: true } } }
]);
Model.watch() (requires replica
set).const changeStream = User.watch();
changeStream.on('change', (change) => console.log('changed', change));
const session = await mongoose.startSession();
await session.withTransaction(async () => {
await User.updateOne({ _id: id1 }, { $inc: { balance: -50 } }, { session });
await Account.updateOne({ _id: id2 }, { $inc: { balance: +50 } }, { session });
});
session.endSession();
// define in schema
userSchema.index({ email: 1 });
// sync indexes
await User.syncIndexes();
// instance method
userSchema.methods.sayHi = function(){ console.log('Hi', this.name); };
// static method
userSchema.statics.findByEmail = function(email){ return this.findOne({ email }); };
const User = mongoose.model('User', userSchema);
const u = await User.findByEmail('a@x.com');
save, validate,
remove, updateOne.userSchema.pre('save', function(next){
if(this.isModified('password')) this.password = hash(this.password);
next();
});
userSchema.post('remove', function(doc){ console.log('removed', doc._id); });
const obj = { _id: '64f...', name:'X' };
const doc = User.hydrate(obj); // doc is a Mongoose document (no DB call)
await User.createCollection({ capped: true, size: 1024 });
save() and create(). For updates use runValidators: true.
{ new: true } to return the updated doc.query.lean() to get plain objects (faster,
no getters/methods).populate() to join references — avoids
manual second queries.syncIndexes() or migrations..select()) for performance.