Docs Home / Node.js Driver / Integrate with Mongoose

Tutorial: Mongoose Get Started教程:Mongoose入门

Overview概述

Mongoose is an Object Data Modeling (ODM) library for MongoDB. You can use Mongoose to help with data modeling, schema enforcement, model validation, and general data manipulation. Because MongoDB has a flexible data model that allows you to alter and update databases in the future, there aren't rigid schemas. Mongoose是MongoDB的对象数据建模(ODM)库。您可以使用Mongoose来帮助进行数据建模、模式实施、模型验证和一般数据操作。因为MongoDB有一个灵活的数据模型,允许您在未来更改和更新数据库,所以没有严格的模式。However, Mongoose enforces a semi-rigid schema from the beginning, so you must define a schema and model.然而,Mongoose从一开始就强制执行半刚性模式,因此您必须定义一个模式和模型。

Schemas模式

A schema defines the structure of your collection documents. A Mongoose schema maps directly to a MongoDB collection.模式定义了集合文档的结构。Mongoose模式直接映射到MongoDB集合。

The following example creates a new Schema named blog:以下示例创建了一个名为blog的新模式:

const blog = new Schema({
title: String,
slug: String,
published: Boolean,
author: String,
content: String,
tags: [String],
comments: [{
user: String,
content: String,
votes: Number
}]
}, {
timestamps: true
});

When you create a schema, you must define each field and its data types. The following types are permitted:创建模式时,必须定义每个字段及其数据类型。允许使用以下类型:

  • String
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • ObjectId
  • Array
  • Int32
  • Decimal128
  • Double
  • Map

Models模型

Models take your schema and apply it to each document in its collection. Models are responsible for all document interactions such as create, read, update, and delete (CRUD) operations.模型采用您的模式并将其应用于其集合中的每个文档。模型负责所有文档交互,如创建、读取、更新和删除(CRUD)操作。

Tip

The first argument you pass to the model is the singular form of your collection name. Mongoose automatically changes this to the plural form, transforms it to lowercase, and uses that for the database collection name.传递给模型的第一个参数是集合名称的单数形式。Mongoose会自动将其更改为复数形式,将其转换为小写,并将其用作数据库集合名称。

The following example shows how to declare a model named Blog that uses the blog schema:以下示例显示了如何声明一个名为Blog的模型,该模型使用blog模式:

const Blog = mongoose.model('Blog', blog);

In the preceding example, Blog translates to the blogs collection in MongoDB.在前面的示例中,Blog转换为MongoDB中的blogs集合。

Tutorial教程

In this tutorial, you will perform the following actions:在本教程中,您将执行以下操作:

  • Set up your environment to use Mongoose设置您的环境以使用Mongoose
  • Connect to MongoDB连接到MongoDB
  • Create a Mongoose schema and model创建Mongoose模式和模型
  • Insert, update, find, and delete data插入、更新、查找和删除数据
  • Project document fields项目文档字段
  • Validate your data验证您的数据
  • Use multiple schemas and middleware使用多种模式和中间件
1

Verify the prerequisites验证先决条件

Before you begin this tutorial, ensure you have the following components prepared:在开始本教程之前,请确保您已准备好以下组件:

  • An MongoDB Atlas account with a configured cluster. To view instructions, see the MongoDB Get Started guide.一个配置了集群的MongoDB Atlas帐户。要查看说明,请参阅MongoDB入门指南
  • Node.js v16.20.1 or later.v16.20.1或更高版本。
2

Set up your environment设置您的环境

This tutorial uses nodemon to run the code locally. Run the following commands in your terminal to initialize your project and install the necessary dependencies:本教程使用nodemon在本地运行代码。在终端中运行以下命令以初始化项目并安装必要的依赖项:

mkdir mongodb-mongoose
cd mongodb-mongoose
npm init -y
npm i mongoose
npm i -D nodemon

Open your project in your preferred code editor. This tutorial uses ES Modules instead of CommonJS. You must add the module type to use ES Modules. Go to the package.json file and add the following code:在您喜欢的代码编辑器中打开您的项目。本教程使用ES模块而不是CommonJS。您必须添加module类型才能使用ES模块。转到package.json文件并添加以下代码:

...
"scripts": {
"dev": "nodemon index.js"
},
"type": "module",
...

Start your application with nodemon by running the following command:通过运行以下命令,使用nodemon启动应用程序:

npm run dev

Note

When you use nodemon, the code runs every time you save a file.当您使用nodemon时,每次保存文件时都会运行代码。

3

Connect to MongoDB连接到MongoDB

In the root level of your project, create a file named index.js and add the following code to the top of the file:在项目的根级别,创建一个名为index.js的文件,并将以下代码添加到文件顶部:

import mongoose from 'mongoose';

mongoose.connect("<connection string>")

Replace the <connection string> placeholder with your MongoDB Atlas connection string. For more information on how to find your connection string, see the Connect to Your Cluster tutorial in the Atlas documentation.<connection-string>占位符替换为MongoDB Atlas连接字符串。有关如何查找连接字符串的更多信息,请参阅Atlas文档中的“连接到集群”教程。

4

Create a schema and a model创建模式和模型

Before you start adding and updating data in MongoDB, you must create a schema and model.在MongoDB中开始添加和更新数据之前,您必须创建一个模式和模型。

With Mongoose, you create a schema model file for each schema that is needed. First, create a folder called model to put all your schema files in, then create your first schema file called Blog.js. Open this file and add the following code:使用Mongoose,您可以为所需的每个模式创建一个模式模型文件。首先,创建一个名为model的文件夹来存放所有模式文件,然后创建第一个名为Blog.js的模式文件。打开此文件并添加以下代码:

import mongoose from 'mongoose';
const { Schema, model } = mongoose;

const blogSchema = new Schema({
title: String,
slug: String,
published: Boolean,
author: String,
content: String,
tags: [String],
comments: [{
user: String,
content: String,
votes: Number
}]
}, {
timestamps: true
});

const Blog = model('Blog', blogSchema);
export default Blog;

This schema enables a timestamps option, which adds mongoose-manged createdAt and updatedAt fields to the schema that are updated automatically. 此模式启用了timestamps(时间戳)选项,该选项将mongose管理的createdAtupdatedAt字段添加到自动更新的模式中。For more information, see the Timestamps page in the Mongoose documentation.有关更多信息,请参阅Mongoose文档中的时间戳页面。

5

Perform CRUD operations执行CRUD操作

You now have your first model and schema set up, and you can start inserting data into the database. The following sections show you how to perform CRUD operations using Mongoose.现在,您已经设置了第一个模型和模式,可以开始将数据插入数据库。以下部分将向您展示如何使用Mongoose执行CRUD操作。

Insert Data插入数据

Go to index.js and add the following import statement to the top of your file:转到index.js并将以下import语句添加到文件顶部:

import Blog from './model/Blog.js';

Add the following code below the line that contains your connection string:在包含连接字符串的行下方添加以下代码:

// Creates a new blog post and inserts it into database
const article = await Blog.create({
title: 'Awesome Post!',
slug: 'awesome-post',
published: true,
content: 'This is the best post ever',
tags: ['featured', 'announcement'],
});

console.log('Created article:', article);

The preceding code uses the Mongoose create() method to instantiate the object representing a blog article, and then saves it to the database. The returned document logs to the console, including its _id. Take note of this _id for use in future steps.前面的代码使用Mongoose create()方法实例化表示博客文章的对象,然后将其保存到数据库中。返回的文档记录到控制台,包括其_id。记下这个_id,以便在以后的步骤中使用。

Update Data更新数据

To update data, you can directly edit the local object with Mongoose. Then, you can use the save() method to write the update to the database.要更新数据,您可以直接使用Mongoose编辑本地对象。然后,您可以使用save()方法将更新写入数据库。

Add the following code to update the article you inserted in the previous section:添加以下代码以更新您在上一节中插入的文章:

// Updates the title of the article
article.title = "The Most Awesomest Post!!";
await article.save();
console.log('Updated Article:', article);
Updated Article: {
title: 'The Most Awesomest Post!!',
slug: 'awesome-post',
published: true,
content: 'This is the best post ever',
tags: [ 'featured', 'announcement' ],
_id: new ObjectId('...'),
comments: [],
__v: 0
}

Find Data查找数据

To find a specific document, you can use the Mongoose findById() method to query for a document by specifying its _id.要查找特定文档,可以使用Mongoose findById()方法通过指定文档的_id来查询文档。

Add following code to your index.js file to find a specific article by its _id:index.js文件中添加以下代码,根据_id查找特定文章:

// Finds the article by its ID. Replace <object id> with the objectId of the article.按文章的ID查找文章。将<object id>替换为文章的objectId。
const articleFound = await Blog.findById("<object id>").exec();
console.log('Found Article by ID:', articleFound);
Found Article by ID: {
_id: new ObjectId('68261c9dae39e390341c367c'),
title: 'The Most Awesomest Post!!',
slug: 'awesome-post',
published: true,
content: 'This is the best post ever',
tags: [ 'featured', 'announcement' ],
comments: [],
__v: 0
}

Note

By default, Mongoose queries return thenables, which are objects with some properties of a JavaScript Promise. You can append the exec() method to a query to receive a true JavaScript Promise. 默认情况下,Mongoose查询返回thenables,它们是具有JavaScript Promise某些属性的对象。您可以将exec()方法附加到查询中以接收真正的JavaScript Promise。To learn more about working with promises in Mongoose, see the Promises guide in the Mongoose documentation.要了解有关在Mongoose中使用promises的更多信息,请参阅Mongoose文档中的promises指南

Specify Document Fields指定文档字段

You can use Mongoose to project only the fields that you need. The following code specifies to only project the title, slug, and content fields.您可以使用Mongoose仅投影所需的字段。以下代码指定仅投影titleslugcontent字段。

Add the following code to your index.js file, replacing the <object id> placeholder with the ObjectId value for the document that you inserted previously:将以下代码添加到index.js文件中,用之前插入的文档的ObjectId值替换<object id>占位符:

// Finds the article by its ID and projects only the title, slug, and content fields.按文章的ID查找文章,并仅投影标题、slug和内容字段。
// Replace <object id> with the objectId of the article.
const articleProject = await Blog.findById("<object id>", "title slug content").exec();
console.log('Projected Article:', articleProject);
Projected Article: {
_id: new ObjectId('...'),
title: 'The Most Awesomest Post!!',
slug: 'awesome-post',
content: 'This is the best post ever'
}

Delete Data删除数据

Mongoose uses the deleteOne() and deleteMany() methods to delete data from a collection. You can specify the field of the document you want to delete and pass that field to the method that you choose.Mongoose使用deleteOne()deleteMany()方法从集合中删除数据。您可以指定要删除的文档的字段,并将该字段传递给您选择的方法。

Add the following code to your index.js file to delete one article from the database:将以下代码添加到indexjs文件中,以从数据库中删除一篇文章:

// Deletes one article with the slug "awesome-post".删除一篇带有“真棒帖子”的文章。
const blogOne = await Blog.deleteOne({ slug: "awesome-post" });
console.log('Deleted One Blog:', blogOne);
Deleted One Blog: { acknowledged: true, deletedCount: 1 }

To delete multiple articles, you can add the following code:要删除多篇文章,可以添加以下代码:

// Deletes all articles with the slug "awesome-post".删除所有带有“真棒帖子”字样的文章。
const blogMany = await Blog.deleteMany({ slug: "awesome-post" });
console.log('Deleted Many Blogs:', blogMany);
Deleted Many Blogs: { acknowledged: true, deletedCount: 4 }
6

Validate your data验证您的数据

The articles inserted in the previous steps do not contain the author, dates, or comments fields, even though these fields are included in the schema. This is because although you defined the structure of your document, you have not defined which fields are required. Any field that is not defined as required can be omitted.在前面的步骤中插入的文章不包含author(作者)、dates(日期)或comments(评论)字段,即使这些字段包含在架构中。这是因为,虽然您定义了文档的结构,但尚未定义哪些字段是必需的。任何未按要求定义的字段都可以省略。

In Mongoose, when you include validation on a field, you must pass an object as its value.在Mongoose中,当您在字段上包含验证时,您必须传递一个对象作为其值。

Note

Validators automatically run on the create() and save() methods. 验证器会自动在create()save()方法上运行。You can specify them to run them on update methods, such as update() and updateOne() by setting the runValidators option to true. 您可以通过将runValidators选项设置为true来指定它们在更新方法上运行,例如update()updateOne()For more information about validators, see the Validation page in the Mongoose documentation.有关验证器的更多信息,请参阅Mongoose文档中的验证页面。

You can use several validation methods with Mongoose. For example, you can set required to true on any fields that you want to require. You can also validate the type and the formatting. 您可以在Mongoose中使用多种验证方法。例如,您可以在任何需要的字段上将required设置为true。您还可以验证类型和格式。In the following code, the slug field is defined as a string with a minLength of 4. This means that providing a slug with fewer than 4 characters will result in a ValidationError.在以下代码中,slug字段被定义为minLength4的字符串。这意味着提供少于4个字符的slug将导致ValidationError

To add data validation and define these requirements, update the schema in Blog.js as shown in the following example:要添加数据验证并定义这些要求,请更新Blog.js中的模式,如下例所示:

const blogSchema = new Schema({
title: {
type: String,
required: true,
},
slug: {
type: String,
required: true,
minLength: 4,
},
published: {
type: Boolean,
default: false,
},
author: {
type: String,
required: true,
},
content: String,
tags: [String],
comments: [{
user: String,
content: String,
votes: Number
}]
}, {
timestamps: true
});

After adding this validation, your application will crash. Add an author field to the create() call in your index.js file to meet the new validation requirement:添加此验证后,您的应用程序将崩溃。在index.js文件的create()调用中添加author(作者)字段,以满足新的验证要求:

// Creates a new blog post and inserts it into database创建新的博客文章并将其插入数据库
const article = await Blog.create({
title: 'Awesome Post!',
slug: 'awesome-post',
published: true,
author: 'A.B. Cee',
content: 'This is the best post ever',
tags: ['featured', 'announcement'],
});

Tip

When you use schemas with Mongoose, value: String is the same as value: {type: String}.当您在Mongoose中使用模式时,value:Stringvalue:{type:String}相同。

For more information, see the Validation page in the Mongoose documentation.有关更多信息,请参阅Mongoose文档中的验证页面。

7

Introduce multiple schemas引入多种模式

Next, you can add more complexity to your author field by creating a another schema, and nesting it in the blog schema.接下来,您可以通过创建另一个模式并将其嵌套在博客模式中来增加author字段的复杂性。

In the model folder, create a new file named User.js. Add the following code to this file:model文件夹中,创建一个名为User.js的新文件。将以下代码添加到此文件中:

import mongoose from 'mongoose';
const {Schema, model} = mongoose;

const userSchema = new Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
minLength: 10,
required: true,
lowercase: true
},
});

const User = model('User', userSchema);
export default User;

To use your new User model to define the author field in the blog schema, update the Blog.js file with the following changes:要使用新的用户模型定义博客模式中的author字段,请使用以下更改更新Blog.js文件:

  • Add SchemaTypes to the list of properties extracted from the Mongoose library.SchemaTypes添加到从Mongoose库提取的属性列表中。
  • Change the author field type to SchemaTypes.ObjectId and add a reference (ref) to the 'User' model.author字段类型更改为SchemaTypes.ObjectId,并向'User'模型添加引用(ref)。

The following code shows these updates:以下代码显示了这些更新:

const { Schema, SchemaTypes, model } = mongoose;

... // Inside Schema block:架构块内部:
author: {
type: SchemaTypes.ObjectId,
ref: 'User',
required: true,
},
...

You can reuse the same User model for the comment.user field by changing the blogSchema definition:您可以通过更改blogSchema定义为comment.user字段重用相同的User模型:

... // Inside Schema block:架构块内部:
comments: [{
user: {
type: SchemaTypes.ObjectId,
ref: 'User',
required: true,
},
...

To use the new user model in your application, go to the index.js file. Add the following code to the top of the file to import the user model:要在应用程序中使用新的用户模型,请转到index.js文件。将以下代码添加到文件顶部以导入用户模型:

import User from './model/User.js';

Because you added field validation to the blog schema, the previous code to insert, update, and delete blogs, and to specify fields to project, won't pass the validation and the application will error.因为您在博客架构中添加了字段验证,所以之前插入、更新和删除博客以及指定要投影的字段的代码将无法通过验证,应用程序将出错。

Create a new user by adding the following create() call:通过添加以下Create()调用创建新用户:

// Create a new user创建新用户
const user = await User.create({
name: 'Jess Garica',
email: 'jgarcia@email.com',
});

Update the existing create() call with the following code to create a new article that uses the new user as the author, as shown in the following code:使用以下代码更新现有的create()调用,以创建一篇使用新用户作为作者的新文章,如以下代码所示:

// Creates a new blog post that references the user as the author创建一篇引用用户作为作者的新博客文章
const articleAuthor = await Blog.create({
title: 'Awesome Post!',
slug: 'Awesome-Post',
author: user._id,
content: 'This is the best post ever',
tags: ['featured', 'announcement'],
});

console.log('Article with Author:', articleAuthor);
Article with Author: {
title: 'Awesome Post!',
slug: 'awesome-post',
published: false,
author: new ObjectId('...'),
content: 'This is the best post ever',
tags: [ 'featured', 'announcement' ],
_id: new ObjectId('...'),
createdAt: 2025-05-15T18:05:23.780Z,
comments: [],
__v: 0
}

The preceding code adds a users collection with the blogs collection in the MongoDB database. This code adds the required author field and sets its value to the user._id.前面的代码在MongoDB数据库中添加了一个users集合和blogs集合。此代码添加了必需的author 字段,并将其值设置为user._id

To add the values of the name and email fields to the author field for the article, you can append the Mongoose populate() method to your Blog query. The populate() method will perform a second query for the User document referenced by user._id.要将nameemail字段的值添加到文章的author字段中,您可以将Mongoose populate()方法附加到您的博客查询中。populate()方法将对用户引用的User文档执行第二次查询。_id

Add the following code to index.js to populate this data:将以下代码添加到index.js中以填充此数据:

// Populates the author field with user data用用户数据填充作者字段
const articlePopulate = await Blog.findOne({ title: "Awesome Post!" }).populate("author");
console.log('Article Populated:', articlePopulate);
Article Populated: {
_id: new ObjectId('...'),
title: 'Awesome Post!',
slug: 'awesome-post',
published: false,
author: {
_id: new ObjectId('...'),
name: 'Jess Garica',
email: 'jgarcia@email.com',
__v: 0
},
content: 'This is the best post ever',
tags: [ 'featured', 'announcement' ],
createdAt: 2025-05-15T18:04:28.590Z,
comments: [],
__v: 0
}

For more information, see the Document.populate() page of the Mongoose API documentation.有关更多信息,请参阅Mongoose API文档的Document.populate()页面。

8

Add middleware添加中间件

In Mongoose, middleware are functions that run before, or during, the execution of asynchronous functions at the schema level.在Mongoose中,中间件是在模式级别执行异步函数之前或期间运行的函数。

One example of middleware is a function that validates the email field of a User instance before saving or updating.中间件的一个例子是在保存或更新之前验证User实例的email字段的函数。

This example uses the validator package. You can install the validator package by running the following command:此示例使用validator包。您可以通过运行以下命令安装validator包:

npm install validator

To add this middleware function, add the following code to the userSchema declaration in your User.js file:要添加此中间件函数,请将以下代码添加到User.js文件中的userSchema声明中:

import validator from 'validator';
userSchema.pre('save', function (next) {
const user = this;

// Normalize email规范电子邮件
if (user.email) {
user.email = user.email.trim().toLowerCase();
}

// Validate email format验证电子邮件格式
if (!validator.isEmail(user.email)) {
return next(new Error('Invalid email format'));
}

next();
});

To see the effect of this function, modify the user.email field in your index.js file to make it an invalid email address:要查看此函数的效果,请修改index.js文件中的user.email字段,使其成为无效的电子邮件地址:

const user = await User.create({
name: 'Jess Garica',
email: 'jgarciaemail.com',
});
Error: Invalid email format

If you correct the email address, you can see that the error is not thrown.如果你更正了电子邮件地址,你可以看到没有抛出错误。

Besides the pre() middleware function, Mongoose also offers a post() middleware function. For more information about middleware, see the Middleware page in the Mongoose documentation.除了pre()中间件函数外,Mongoose还提供了post()中间件功能。有关中间件的更多信息,请参阅Mongoose文档中的中间件页面。

Next Steps后续步骤

You now have a sample project that uses Mongoose to perform CRUD operations on a MongoDB collection. From here, you can choose to build on this project with more complex queries or document validation. The following sections includes some examples of Mongoose features that you might use to in your application.现在,您有一个使用Mongoose对MongoDB集合执行CRUD操作的示例项目。从这里,您可以选择使用更复杂的查询或文档验证来构建此项目。以下部分包括您可能在应用程序中使用的Mongoose功能的一些示例。

Mongoose Custom SettersMongoose定制套装

Custom setters modify your data when it is saved, and can be implemented similar to validators. Mongoose provides the following custom setters:自定义设置程序在保存数据时对其进行修改,并且可以类似于验证器来实现。Mongoose提供以下自定义设置程序:

  • lowercase
  • uppercase
  • trim

The following example lowercases the characters in the blog.slug field:以下示例降低了blog.slug字段中的字符:

const blogSchema = new Schema({
...
slug: {
type: String,
required: true,
minLength: 4,
lowercase: true,
},
...
});

For more information, see the SchemaStringOptions page in the Mongoose API documentation.有关更多信息,请参阅Mongoose API文档中的SchemaStringOptions页面。

Helper Methods帮助方法

Mongoose includes several helper methods that are abstracted from regular MongoDB methods. In this section, you can find examples of some of these methods. These methods are not used specifically in this tutorial, but they are helpful to reference when getting started with Mongoose.Mongoose包括几个从常规MongoDB方法中抽象出来的辅助方法。在本节中,您可以找到其中一些方法的示例。本教程中没有具体使用这些方法,但在开始使用Mongoose时可以参考它们。

exists()

The exists() method returns either null or the first document that matches the provided query. The following is an example of matching an article based on the author field:exists()方法返回null或与提供的查询匹配的第一个文档。以下是一个基于作者字段匹配文章的示例:

const blog = await Blog.exists({ author: 'Jess Garcia' });
console.log(blog);

For more information, see the Model.exists() section of the Mongoose API documentation.有关更多信息,请参阅Mongoose API文档的Model.exists()部分。

where()

The where() method allows you to chain and build complex queries.where()方法允许您链接和构建复杂的查询。

The following is an example of performing a find operation by using findOne() with a plain query object and the equivalent query with the where() method:以下是一个使用findOne()和一个普通查询对象执行查找操作的示例,以及使用where()方法执行等效查询的示例:

const blogFind = await Blog.findOne({ author: "Jess Garcia" });
console.log(blogFind);

const blogWhere = await Blog.findOne().where("author").equals("Jess Garcia");
console.log(blogWhere);

In this implementation, the where() implementation starts with a findOne() which tells Mongoose to treat it as a findOne() query. This is important because if you use where() on its own (Blog.where(...)), Mongoose implicitly treats it as a find() operation.在这个实现中,where()实现从一个findOne()开始,它告诉Mongoose将其视为一个findOne()查询。这很重要,因为如果你单独使用where()Blog.where(...)),Mongoose会隐式地将其视为find()操作。

Generally, the where() method is used for complex queries involving dynamic query building or multiple comparators, or when using this method improves readability. There is no performance difference between using the where() method or a plain object query.通常,where()方法用于涉及动态查询构建或多个比较器的复杂查询,或者在使用此方法时提高可读性。使用where()方法和普通对象查询之间没有性能差异。

To include projection when using the where() method, chain the select() method after your query, as shown in the following example:要在使用where()方法时包含投影,请在查询后链接select()方法,如下例所示:

const blog = await Blog.findOne().where("author").equals("Jess Garcia").select("title author");
console.log(blog);

For more information, see the following sections of the Mongoose API documentation:有关更多信息,请参阅Mongoose API文档的以下部分:

Additional Resources其他资源

To learn more about using Mongoose with MongoDB, see the Mongoose documentation.要了解有关在MongoDB中使用Mongoose的更多信息,请参阅Mongoose文档

To find support or to contribute to the MongoDB community, see the MongoDB Developer Community page.要寻求支持或为MongoDB社区做出贡献,请参阅MongoDB开发人员社区页面。