Mongoose
Mongoose 是一个 MongoDB 对象建模工具,旨在异步环境中运行。Mongoose 支持 Node.js 和 Deno(alpha)。
文档
官方文档网站是 mongoosejs.com。
Mongoose 9.0.0 于 2025 年 11 月 21 日发布。您可以在 我们文档网站上查看 9.0.0 中的向后不兼容更改 以获取更多详细信息。
支持
插件
请访问 插件搜索网站 查看社区提供的数百个相关模块。接下来,从 文档 或 这篇博客文章 中学习如何编写自己的插件。
贡献者
始终欢迎 Pull requests!请基于 master
分支创建 pull request,并遵循 贡献指南。
如果您的 pull request 包含文档更改,请不要
修改任何 .html 文件。.html 文件是编译后的代码,因此请在 docs/*.pug、lib/*.js 或 test/docs/*.js 中进行更改。
查看全部 400 多位 贡献者。
安装
首先安装 Node.js 和 MongoDB,然后使用您首选的包管理器安装 mongoose 包:
使用 npm
npm install mongoose
使用 pnpm
pnpm add mongoose
使用 Yarn
yarn add mongoose
使用 Bun
bun add mongoose
Mongoose 6.8.0 还包含对 Deno 的 alpha 支持。
导入
// Using Node.js `require()`
const mongoose = require('mongoose');
// Using ES6 imports
import mongoose from 'mongoose';
或者,如下使用 Deno 的 createRequire() 以支持 CommonJS。
import { createRequire } from 'https://deno.land/std@0.177.0/node/module.ts';
const require = createRequire(import.meta.url);
const mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1:27017/test')
.then(() => console.log('Connected!'));
然后你可以使用以下命令运行上述脚本。
deno run --allow-net --allow-read --allow-sys --allow-env mongoose-test.js
Mongoose Studio
Mongoose Studio 是一款由 Mongoose 团队开发的免费、完全开源的基于浏览器的 MongoDB GUI,专为已使用 Mongoose 的应用而设计。从 npm 安装 @mongoosejs/studio 并将其作为 Express 中间件与您的应用一起运行,或将其部署到 Vercel 或 Netlify,以浏览和编辑文档,使用现有的模型和模式进行带自动补全的查询,构建仪表板,可视化和编辑 GeoJSON,并使用 AI 辅助的 MongoDB 工作流,而无需将数据迁移到托管的第三方工作区或共享原始 MongoDB 连接字符串。
Mongoose for Enterprise
作为 Tidelift Subscription 的一部分提供
mongoose 的维护者以及数千个其他包的维护者正在与 Tidelift 合作,为您用于构建应用程序的开源依赖项提供商业支持和维护。在支付您实际使用的依赖项维护者的同时,节省时间、降低风险并改善代码健康状况。了解更多。
概述
连接到 MongoDB
首先,我们需要定义一个连接。如果您的应用只使用一个数据库,您应该使用 mongoose.connect。如果需要创建额外的连接,请使用 mongoose.createConnection。
connect 和 createConnection 都接受一个 mongodb:// URI,或者参数 host, database, port, options。
await mongoose.connect('mongodb://127.0.0.1/my_database');
连接成功后,会在 Connection 实例上触发 open 事件。如果你使用的是 mongoose.connect,则 Connection 为 mongoose.connection。否则,mongoose.createConnection 的返回值是一个 Connection。
注意: 如果本地连接失败,请尝试使用 127.0.0.1 代替 localhost。有时,当本地主机名被更改时可能会出现一些问题。
重要! Mongoose 会缓冲所有命令,直到它连接到数据库。这意味着你不必等到它连接到 MongoDB 才能定义模型、运行查询等。
定义模型
模型通过 Schema 接口定义。
const Schema = mongoose.Schema;
const ObjectId = Schema.ObjectId;
const BlogPost = new Schema({
author: ObjectId,
title: String,
body: String,
date: Date
});
除了定义文档的结构和所存储的数据类型外,Schema 还负责定义以下内容:
以下示例展示了其中一些功能:
const Comment = new Schema({
name: { type: String, default: 'hahaha' },
age: { type: Number, min: 18, index: true },
bio: { type: String, match: /[a-z]/ },
date: { type: Date, default: Date.now },
buff: Buffer
});
// a setter
Comment.path('name').set(function(v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function(next) {
notify(this.get('email'));
next();
});
访问模型
一旦我们通过 mongoose.model('ModelName', mySchema) 定义了一个模型,我们就可以通过同一个函数访问它
const MyModel = mongoose.model('ModelName');
或者一次性全部完成
const MyModel = mongoose.model('ModelName', mySchema);
第一个参数是你的模型所对应的集合的单数名称。Mongoose 会自动查找你的模型名称的复数形式。 例如,如果你使用
const MyModel = mongoose.model('Ticket', mySchema);
然后 MyModel 将使用 tickets 集合,而不是 ticket 集合。更多详情请参阅 model docs。
一旦我们有了模型,就可以实例化它并保存:
const instance = new MyModel();
instance.my.key = 'hello';
await instance.save();
或者我们可以从同一集合中查找文档
await MyModel.find({});
你也可以 findOne、findById、update 等。
const instance = await MyModel.findOne({ /* ... */ });
console.log(instance.my.key); // 'hello'
有关更多详细信息,请参阅文档。
重要! 如果你使用 mongoose.createConnection() 打开了一个单独的连接,但试图通过 mongoose.model('ModelName') 访问模型,它将无法按预期工作,因为它未连接到活动的数据库连接。在这种情况下,请通过你创建的连接访问你的模型:
const conn = mongoose.createConnection('your connection string');
const MyModel = conn.model('ModelName', schema);
const m = new MyModel();
await m.save(); // works
vs
const conn = mongoose.createConnection('your connection string');
const MyModel = mongoose.model('ModelName', schema);
const m = new MyModel();
await m.save(); // does not work b/c the default connection object was never connected
嵌入式文档
在第一个示例代码片段中,我们在 Schema 中定义了一个键,其形式如下:
comments: [Comment]
其中 Comment 是我们创建的 Schema。这意味着创建嵌入式文档非常简单:
// retrieve my model
const BlogPost = mongoose.model('BlogPost');
// create a blog post
const post = new BlogPost();
// create a comment
post.comments.push({ title: 'My comment' });
await post.save();
删除它们也是如此:
const post = await BlogPost.findById(myId);
post.comments[0].deleteOne();
await post.save();
嵌入式文档享有与您的模型完全相同的功能。默认值、验证器、中间件。
中间件
请参阅 docs 页面。
拦截和修改方法参数
您可以通过中间件拦截方法参数。
例如,这将允许您每当有人将您文档中的某个路径 set 为新值时,广播关于您文档的变更:
schema.pre('set', function(next, path, val, typel) {
// `this` is the current Document
this.emit('set', path, val);
// Pass control to the next pre
next();
});
此外,你可以修改传入的 method 参数,使得后续中间件看到这些参数的不同值。为此,只需将新值传递给 next:
schema.pre(method, function firstPre(next, methodArg1, methodArg2) {
// Mutate methodArg1
next('altered-' + methodArg1.toString(), methodArg2);
});
// pre declaration is chainable
schema.pre(method, function secondPre(next, methodArg1, methodArg2) {
console.log(methodArg1);
// => 'altered-originalValOfMethodArg1'
console.log(methodArg2);
// => 'originalValOfMethodArg2'
// Passing no arguments to `next` automatically passes along the current argument values
// i.e., the following `next()` is equivalent to `next(methodArg1, methodArg2)`
// and also equivalent to, with the example method arg
// values, `next('altered-originalValOfMethodArg1', 'originalValOfMethodArg2')`
next();
});
Schema 陷阱
type 在 Schema 中使用时,在 Mongoose 内部具有特殊含义。如果您的 Schema 需要将其作为嵌套属性使用 type,则必须使用对象表示法:
new Schema({
broken: { type: Boolean },
asset: {
name: String,
type: String // uh oh, it broke. asset will be interpreted as String
}
});
new Schema({
works: { type: Boolean },
asset: {
name: String,
type: { type: String } // works. asset is an object with a type property
}
});
驱动程序访问
Mongoose 构建于 官方 MongoDB Node.js 驱动程序 之上。每个 mongoose 模型都保留对 原生 MongoDB 驱动程序集合 的引用。可以使用 YourModel.collection 访问集合对象。然而,直接使用集合对象会绕过所有 mongoose 功能,包括钩子、验证等。一个
值得注意的例外是,YourModel.collection 仍然会缓冲
命令。因此,YourModel.collection.find() 将不
返回游标。
API 文档
Mongoose API 文档,使用 dox 和 acquit 生成。
相关项目
MongoDB 运行器
非官方 CLI
数据填充
Express 会话存储
许可证
Copyright (c) 2010 LearnBoost <dev@learnboost.com>
特此授予任何获得本软件及相关文档文件(“软件”)副本的人, 免费地、无限制地处理软件的权利,包括但不限于使用、复制、修改、合并、发布、 分发、再许可和/或销售软件副本的权利,并允许向其提供软件的人这样做,但须 遵守以下条件:
上述版权声明和本许可声明应包含在软件的所有副本或重要部分中。
软件按“原样”提供,不提供任何形式的保证, 无论是明示的还是默示的,包括但不限于对 适销性、特定用途适用性和非侵权性的保证。 在任何情况下,作者或版权持有人均不对任何 索赔、损害或其他责任负责,无论是基于合同、 侵权或其他行为,均源于或与 软件或软件的使用或其他交易有关。
