The creation and use of models
Creation and Usage of Models
In Mongoose, models are instances of Schema used to interact with MongoDB collections. Models provide methods for creating, querying, updating, and deleting documents, making them one of the core functionalities of Mongoose.
Defining a Schema
Before creating a model, you must first define a Schema. A Schema defines the structure of a document, including field types, default values, and validation rules.
const mongoose = require('mongoose');
const { Schema } = mongoose;
const userSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
minlength: 3,
maxlength: 20
},
email: {
type: String,
required: true,
unique: true,
match: /^\S+@\S+\.\S+$/
},
age: {
type: Number,
min: 18,
max: 120
},
createdAt: {
type: Date,
default: Date.now
},
isActive: {
type: Boolean,
default: true
}
});
Creating a Model
Use the mongoose.model()
method to compile a Schema into a model. The model name is typically singular, and Mongoose automatically converts it to plural for the collection name.
const User = mongoose.model('User', userSchema);
You can also specify a custom collection name:
const User = mongoose.model('User', userSchema, 'custom_users');
Model Methods
Models provide various methods to interact with the database:
Creating Documents
// Create a single document
const newUser = new User({
username: 'john_doe',
email: 'john@example.com',
age: 30
});
newUser.save()
.then(doc => console.log(doc))
.catch(err => console.error(err));
// Or use the create method
User.create({
username: 'jane_doe',
email: 'jane@example.com',
age: 28
})
.then(doc => console.log(doc))
.catch(err => console.error(err));
Querying Documents
// Find all documents
User.find({})
.then(users => console.log(users))
.catch(err => console.error(err));
// Query with conditions
User.find({ age: { $gte: 25 } })
.then(users => console.log(users))
.catch(err => console.error(err));
// Find a single document
User.findOne({ username: 'john_doe' })
.then(user => console.log(user))
.catch(err => console.error(err));
// Find by ID
User.findById('507f1f77bcf86cd799439011')
.then(user => console.log(user))
.catch(err => console.error(err));
Updating Documents
// Update a single document
User.updateOne(
{ username: 'john_doe' },
{ $set: { age: 31 } }
)
.then(result => console.log(result))
.catch(err => console.error(err));
// Update multiple documents
User.updateMany(
{ isActive: true },
{ $set: { lastLogin: new Date() } }
)
.then(result => console.log(result))
.catch(err => console.error(err));
// findByIdAndUpdate
User.findByIdAndUpdate(
'507f1f77bcf86cd799439011',
{ $inc: { age: 1 } },
{ new: true } // Returns the updated document
)
.then(user => console.log(user))
.catch(err => console.error(err));
Deleting Documents
// Delete a single document
User.deleteOne({ username: 'john_doe' })
.then(result => console.log(result))
.catch(err => console.error(err));
// Delete multiple documents
User.deleteMany({ isActive: false })
.then(result => console.log(result))
.catch(err => console.error(err));
// findByIdAndDelete
User.findByIdAndDelete('507f1f77bcf86cd799439011')
.then(user => console.log(user))
.catch(err => console.error(err));
Static Methods
You can define static methods on the model:
userSchema.statics.findByUsername = function(username) {
return this.find({ username: new RegExp(username, 'i') });
};
// Using the static method
User.findByUsername('john')
.then(users => console.log(users))
.catch(err => console.error(err));
Instance Methods
You can also define methods on document instances:
userSchema.methods.getProfile = function() {
return {
username: this.username,
email: this.email,
memberSince: this.createdAt.toLocaleDateString()
};
};
// Using the instance method
User.findOne({ username: 'john_doe' })
.then(user => {
if (user) {
console.log(user.getProfile());
}
})
.catch(err => console.error(err));
Query Builder
Mongoose provides a chainable query builder:
User.find()
.where('age').gte(18).lte(65)
.where('isActive').equals(true)
.sort('-createdAt')
.limit(10)
.select('username email age')
.exec()
.then(users => console.log(users))
.catch(err => console.error(err));
Middleware
You can add middleware before or after model operations:
// Pre-save preprocessing
userSchema.pre('save', function(next) {
if (this.isModified('email')) {
this.email = this.email.toLowerCase();
}
next();
});
// Post-find processing
userSchema.post('find', function(docs) {
console.log(`Found ${docs.length} users`);
});
Virtual Properties
Virtual properties are not stored in the database but can be accessed like regular properties:
userSchema.virtual('fullName').get(function() {
return `${this.firstName} ${this.lastName}`;
});
userSchema.virtual('fullName').set(function(name) {
const [firstName, lastName] = name.split(' ');
this.firstName = firstName;
this.lastName = lastName;
});
const user = new User();
user.fullName = 'John Doe';
console.log(user.firstName); // 'John'
console.log(user.lastName); // 'Doe'
console.log(user.fullName); // 'John Doe'
Indexes
You can define indexes in the Schema:
userSchema.index({ username: 1 }, { unique: true });
userSchema.index({ email: 1 }, { unique: true });
userSchema.index({ age: 1, isActive: 1 });
Model Validation
Mongoose provides built-in validators:
const productSchema = new Schema({
name: {
type: String,
required: [true, 'Product name is required'],
trim: true
},
price: {
type: Number,
required: true,
min: [0, 'Price cannot be less than 0']
},
stock: {
type: Number,
default: 0,
validate: {
validator: Number.isInteger,
message: 'Stock must be an integer'
}
},
category: {
type: String,
enum: {
values: ['Electronics', 'Clothing', 'Food'],
message: 'Invalid product category'
}
}
});
Relationships
Mongoose supports document relationships:
const orderSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
products: [{
product: {
type: Schema.Types.ObjectId,
ref: 'Product'
},
quantity: Number
}],
totalAmount: Number
});
// Populating related data
Order.findById(orderId)
.populate('user')
.populate('products.product')
.exec()
.then(order => console.log(order))
.catch(err => console.error(err));
Pagination
Common pattern for pagination queries:
const getUsers = async (page = 1, limit = 10) => {
const skip = (page - 1) * limit;
const [users, total] = await Promise.all([
User.find().skip(skip).limit(limit),
User.countDocuments()
]);
return {
users,
total,
pages: Math.ceil(total / limit),
currentPage: page
};
};
Transactions
Mongoose supports MongoDB transactions:
const session = await mongoose.startSession();
session.startTransaction();
try {
const user = await User.create([{ username: 'new_user' }], { session });
await Order.create([{ user: user[0]._id, total: 100 }], { session });
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
session.endSession();
}
Aggregation Pipeline
Using the aggregation framework for complex queries:
User.aggregate([
{ $match: { isActive: true } },
{ $group: {
_id: '$ageGroup',
count: { $sum: 1 },
averageAge: { $avg: '$age' }
}},
{ $sort: { count: -1 } }
])
.then(results => console.log(results))
.catch(err => console.error(err));
Performance Optimization
Performance optimization tips for model usage:
- Query only the required fields:
User.find().select('username email -_id')
- Use lean() to return plain JavaScript objects:
User.find().lean()
- Use indexes appropriately:
userSchema.index({ createdAt: -1 });
- Use bulkWrite for batch operations:
User.bulkWrite([
{ insertOne: { document: { username: 'user1' } } },
{ updateOne: { filter: { username: 'user2' }, update: { $set: { age: 30 } } } }
])
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn