阿里云主机折上折
  • 微信号
Current Site:Index > The creation and use of models

The creation and use of models

Author:Chuan Chen 阅读数:25361人阅读 分类: MongoDB

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:

  1. Query only the required fields:
User.find().select('username email -_id')
  1. Use lean() to return plain JavaScript objects:
User.find().lean()
  1. Use indexes appropriately:
userSchema.index({ createdAt: -1 });
  1. Use bulkWrite for batch operations:
User.bulkWrite([
  { insertOne: { document: { username: 'user1' } } },
  { updateOne: { filter: { username: 'user2' }, update: { $set: { age: 30 } } } }
])

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.