从 5.x 迁移到 6.x
¥Migrating from 5.x to 6.x
请注意:我们计划于 2024 年 3 月 1 日停止对 Mongoose 5 的支持。请参阅我们的 版本支持指南。
¥Please note: we plan to discontinue Mongoose 5 support on March 1, 2024. Please see our version support guide.
从 Mongoose 5.x 迁移到 Mongoose 6.x 时,你应该注意几个 向后突破的变化。
¥There are several backwards-breaking changes you should be aware of when migrating from Mongoose 5.x to Mongoose 6.x.
如果你仍在使用 Mongoose 4.x,请先阅读 Mongoose 4.x 到 5.x 迁移指南 并升级到 Mongoose 5.x。
¥If you're still on Mongoose 4.x, please read the Mongoose 4.x to 5.x migration guide and upgrade to Mongoose 5.x first.
简化的
isValidObjectId()
和单独的isObjectIdOrHexString()
¥Simplified
isValidObjectId()
and separateisObjectIdOrHexString()
删除了
omitUndefined
:Mongoose 现在删除更新中的undefined
键,而不是将它们设置为null
SchemaType
set
参数现在使用priorValue
作为第二个参数,而不是self
¥SchemaType
set
parameters now usepriorValue
as the second parameter instead ofself
MongoDB 驱动程序的新 URL 解析器与某些 npm 包不兼容
¥MongoDB Driver's New URL Parser Incompatible with Some npm Packages
版本要求
¥Version Requirements
Mongoose 现在需要 Node.js >= 12.0.0。Mongoose 仍然支持 MongoDB 服务器版本回溯至 3.0.0。
¥Mongoose now requires Node.js >= 12.0.0. Mongoose still supports MongoDB server versions back to 3.0.0.
MongoDB 驱动 4.0
¥MongoDB Driver 4.0
Mongoose 现在使用 MongoDB Node 驱动程序 的 v4.x。详细信息请参见 MongoDB Node 驱动程序迁移指南。以下是一些最值得注意的变化:
¥Mongoose now uses v4.x of the MongoDB Node driver. See the MongoDB Node drivers' migration guide for detailed info. Below are some of the most noteworthy changes:
MongoDB Driver 4.x 是用 TypeScript 编写的,并且有自己的 TypeScript 类型定义。这些可能与
@types/mongodb
冲突,因此如果你遇到 TypeScript 编译器错误,请确保升级到 最新版本@types/mongodb
,这是一个空存根。¥MongoDB Driver 4.x is written in TypeScript and has its own TypeScript type definitions. These may conflict with
@types/mongodb
, so if you have TypeScript compiler errors please make sure you upgrade to the latest version of@types/mongodb
, which is an empty stub.用于连接的
poolSize
选项已变为 替换为minPoolSize
和maxPoolSize
。Mongoose 5.xpoolSize
选项相当于 Mongoose 6maxPoolSize
选项。maxPoolSize
的默认值已增加到 100。¥The
poolSize
option for connections has been replaced withminPoolSize
andmaxPoolSize
. The Mongoose 5.xpoolSize
option is equivalent to the Mongoose 6maxPoolSize
option. The default value ofmaxPoolSize
has been increased to 100.现在
updateOne()
和updateMany()
的结果不同了。¥The result of
updateOne()
andupdateMany()
is now different.deleteOne()
和deleteMany()
的结果不再具有n
属性。¥The result of
deleteOne()
anddeleteMany()
no longer has ann
property.
const res = await TestModel.updateMany({}, { someProperty: 'someValue' });
res.matchedCount; // Number of documents that were found that match the filter. Replaces `res.n`
res.modifiedCount; // Number of documents modified. Replaces `res.nModified`
res.upsertedCount; // Number of documents upserted. Replaces `res.upserted`
const res = await TestModel.deleteMany({});
// In Mongoose 6: `{ acknowledged: true, deletedCount: 2 }`
// In Mongoose 5: `{ n: 2, ok: 1, deletedCount: 2 }`
res;
res.deletedCount; // Number of documents that were deleted. Replaces `res.n`
不再有弃用警告选项
¥No More Deprecation Warning Options
useNewUrlParser
、useUnifiedTopology
、useFindAndModify
和 useCreateIndex
不再受支持的选项。Mongoose 6 的行为始终如同 useNewUrlParser
、useUnifiedTopology
和 useCreateIndex
是 true
,而 useFindAndModify
是 false
。请从你的代码中删除这些选项。
¥useNewUrlParser
, useUnifiedTopology
, useFindAndModify
, and useCreateIndex
are no longer supported options. Mongoose 6 always behaves as if useNewUrlParser
, useUnifiedTopology
, and useCreateIndex
are true
, and useFindAndModify
is false
. Please remove these options from your code.
// No longer necessary:
mongoose.set('useFindAndModify', false);
await mongoose.connect('mongodb://127.0.0.1:27017/test', {
useNewUrlParser: true, // <-- no longer necessary
useUnifiedTopology: true // <-- no longer necessary
});
asPromise()
连接方法
¥The asPromise()
Method for Connections
Mongoose 连接不再是 thenable。这意味着 await mongoose.createConnection(uri)
不再等待 Mongoose 连接。请改用 mongoose.createConnection(uri).asPromise()
。参见 #8810。
¥Mongoose connections are no longer thenable. This means that await mongoose.createConnection(uri)
no longer waits for Mongoose to connect. Use mongoose.createConnection(uri).asPromise()
instead. See #8810.
// The below no longer works in Mongoose 6
await mongoose.createConnection(uri);
// Do this instead
await mongoose.createConnection(uri).asPromise();
mongoose.connect()
返回 Promise
¥mongoose.connect()
Returns a Promise
mongoose.connect()
函数现在总是返回一个 promise,而不是 Mongoose 实例。
¥The mongoose.connect()
function now always returns a promise, not a Mongoose instance.
重复查询执行
¥Duplicate Query Execution
Mongoose 不再允许执行同一查询对象两次。如果这样做,你将收到 Query was already executed
错误。执行相同的查询实例两次通常表示混合回调和 promise,但如果你需要执行相同的查询两次,你可以调用 Query#clone()
来克隆查询并重新执行它。见 gh-7398
¥Mongoose no longer allows executing the same query object twice. If you do, you'll get a Query was already executed
error. Executing the same query instance twice is typically indicative of mixing callbacks and promises, but if you need to execute the same query twice, you can call Query#clone()
to clone the query and re-execute it. See gh-7398
// Results in 'Query was already executed' error, because technically this `find()` query executes twice.
await Model.find({}, function(err, result) {});
const q = Model.find();
await q;
await q.clone(); // Can `clone()` the query to allow executing the query again
Model.exists(...)
现在返回精简文档而不是布尔值
¥Model.exists(...)
now returns a lean document instead of boolean
// in Mongoose 5.x, `existingUser` used to be a boolean
// now `existingUser` will be either `{ _id: ObjectId(...) }` or `null`.
const existingUser = await User.exists({ name: 'John' });
if (existingUser) {
console.log(existingUser._id);
}
默认情况下,strictQuery
现在等于 strict
¥strictQuery
is now equal to strict
by default
Mongoose no longer supports a 从 Mongoose 6.0.10 开始,我们恢复了 strictQuery
option. You must now use strict
.strictQuery
选项。在 Mongoose 6 中,strictQuery
默认设置为 strict
。这意味着,默认情况下,Mongoose 将过滤掉结构中不存在的查询过滤器属性。
¥Mongoose no longer supports a
As of Mongoose 6.0.10, we brought back the strictQuery
option. You must now use strict
.strictQuery
option. In Mongoose 6, strictQuery
is set to strict
by default. This means that, by default, Mongoose will filter out query filter properties that are not in the schema.
但是,这种行为在某些情况下会引起混淆,因此在 Mongoose 7 中,此默认值会更改回 false
。因此,如果你想保留 Mongoose 5 以及 Mongoose 7 及更高版本的默认行为,你也可以全局禁用 strictQuery
以覆盖:
¥However, this behavior was a source of confusion in some cases, so in Mongoose 7, this default changes back to false
. So if you want to retain the default behavior of Mongoose 5 as well as Mongoose 7 and later, you can also disable strictQuery
globally to override:
mongoose.set('strictQuery', false);
在测试套件中,将 strictQuery
设置为 throw
可能很有用,这样当查询引用不存在的模式时就会抛出异常,这有助于识别测试或代码中的错误。
¥In a test suite, it may be useful to set strictQuery
to throw
, which will throw exceptions any time a query references schema that doesn't exist, which could help identify a bug in your tests or code.
以下是 strictQuery
效果的一个示例:
¥Here's an example of the effect of strictQuery
:
const userSchema = new Schema({ name: String });
const User = mongoose.model('User', userSchema);
// By default, this is equivalent to `User.find()` because Mongoose filters out `notInSchema`
await User.find({ notInSchema: 1 });
// Set `strictQuery: false` to opt in to filtering by properties that aren't in the schema
await User.find({ notInSchema: 1 }, null, { strictQuery: false });
// equivalent:
await User.find({ notInSchema: 1 }).setOptions({ strictQuery: false });
你还可以全局禁用 strictQuery
来覆盖:
¥You can also disable strictQuery
globally to override:
mongoose.set('strictQuery', false);
MongoError 现在是 MongoServerError
¥MongoError is now MongoServerError
在 MongoDB Node.js 驱动程序 v4.x 中,'MongoError' 现在是 'MongoServerError'。请更改依赖于硬编码字符串 'MongoError' 的任何代码。
¥In MongoDB Node.js Driver v4.x, 'MongoError' is now 'MongoServerError'. Please change any code that depends on the hardcoded string 'MongoError'.
默认情况下克隆鉴别器模式
¥Clone Discriminator Schemas By Default
Mongoose 现在默认克隆鉴别器结构。这意味着如果你使用递归嵌入式鉴别器,则需要将 { clone: false }
传递到 discriminator()
。
¥Mongoose now clones discriminator schemas by default. This means you need to pass { clone: false }
to discriminator()
if you're using recursive embedded discriminators.
// In Mongoose 6, these two are equivalent:
User.discriminator('author', authorSchema);
User.discriminator('author', authorSchema.clone());
// To opt out if `clone()` is causing issues, pass `clone: false`
User.discriminator('author', authorSchema, { clone: false });
简化的 isValidObjectId()
和单独的 isObjectIdOrHexString()
¥Simplified isValidObjectId()
and separate isObjectIdOrHexString()
在 Mongoose 5 中,对于数字等值,mongoose.isValidObjectId()
返回 false
,这与 MongoDB 驱动程序的 ObjectId.isValid()
函数不一致。从技术上讲,任何 JavaScript 数字都可以转换为 MongoDB ObjectId。
¥In Mongoose 5, mongoose.isValidObjectId()
returned false
for values like numbers, which was inconsistent with the MongoDB driver's ObjectId.isValid()
function.
Technically, any JavaScript number can be converted to a MongoDB ObjectId.
在 Mongoose 6 中,mongoose.isValidObjectId()
只是 mongoose.Types.ObjectId.isValid()
的封装,以保持一致性。
¥In Mongoose 6, mongoose.isValidObjectId()
is just a wrapper for mongoose.Types.ObjectId.isValid()
for consistency.
Mongoose 6.2.5 现在包含 mongoose.isObjectIdOrHexString()
函数,它可以更好地捕获 isValidObjectId()
的更常见用例:给定值是 ObjectId
实例还是代表 ObjectId
的 24 个字符的十六进制字符串?
¥Mongoose 6.2.5 now includes a mongoose.isObjectIdOrHexString()
function, which does a better job of capturing the more common use case for isValidObjectId()
: is the given value an ObjectId
instance or a 24 character hex string representing an ObjectId
?
// `isValidObjectId()` returns `true` for some surprising values, because these
// values are _technically_ ObjectId representations
mongoose.isValidObjectId(new mongoose.Types.ObjectId()); // true
mongoose.isValidObjectId('0123456789ab'); // true
mongoose.isValidObjectId(6); // true
mongoose.isValidObjectId(new User({ name: 'test' })); // true
// `isObjectIdOrHexString()` instead only returns `true` for ObjectIds and 24
// character hex strings.
mongoose.isObjectIdOrHexString(new mongoose.Types.ObjectId()); // true
mongoose.isObjectIdOrHexString('62261a65d66c6be0a63c051f'); // true
mongoose.isObjectIdOrHexString('0123456789ab'); // false
mongoose.isObjectIdOrHexString(6); // false
结构定义的文档键顺序
¥Schema Defined Document Key Order
Mongoose 现在按照结构中指定键的顺序保存带有键的对象,而不是按照用户定义的对象。因此,Object.keys(new User({ name: String, email: String }).toObject()
是 ['name', 'email']
还是 ['email', 'name']
取决于 name
和 email
在你的结构中定义的顺序。
¥Mongoose now saves objects with keys in the order the keys are specified in the schema, not in the user-defined object. So whether Object.keys(new User({ name: String, email: String }).toObject()
is ['name', 'email']
or ['email', 'name']
depends on the order name
and email
are defined in your schema.
const schema = new Schema({
profile: {
name: {
first: String,
last: String
}
}
});
const Test = db.model('Test', schema);
const doc = new Test({
profile: { name: { last: 'Musashi', first: 'Miyamoto' } }
});
// Note that 'first' comes before 'last', even though the argument to `new Test()` flips the key order.
// Mongoose uses the schema's key order, not the provided objects' key order.
assert.deepEqual(Object.keys(doc.toObject().profile.name), ['first', 'last']);
sanitizeFilter
和 trusted()
¥sanitizeFilter
and trusted()
Mongoose 6 为全局变量和查询引入了新的 sanitizeFilter
选项,可以防御 查询选择器注入攻击。如果启用 sanitizeFilter
,Mongoose 会将查询过滤器中的任何对象封装在 $eq
中:
¥Mongoose 6 introduces a new sanitizeFilter
option to globals and queries that defends against query selector injection attacks. If you enable sanitizeFilter
, Mongoose will wrap any object in the query filter in a $eq
:
// Mongoose will convert this filter into `{ username: 'val', pwd: { $eq: { $ne: null } } }`, preventing
// a query selector injection.
await Test.find({ username: 'val', pwd: { $ne: null } }).setOptions({ sanitizeFilter: true });
要显式允许查询选择器,请使用 mongoose.trusted()
:
¥To explicitly allow a query selector, use mongoose.trusted()
:
// `mongoose.trusted()` allows query selectors through
await Test.find({ username: 'val', pwd: mongoose.trusted({ $ne: null }) }).setOptions({ sanitizeFilter: true });
删除了 omitUndefined
:Mongoose 现在删除更新中的 undefined
键,而不是将它们设置为 null
¥Removed omitUndefined
: Mongoose now removes undefined
keys in updates instead of setting them to null
在 Mongoose 5.x 中,在更新操作中将密钥设置为 undefined
相当于将其设置为 null
。
¥In Mongoose 5.x, setting a key to undefined
in an update operation was equivalent to setting it to null
.
let res = await Test.findOneAndUpdate({}, { $set: { name: undefined } }, { new: true });
res.name; // `null` in Mongoose 5.x
// Equivalent to `findOneAndUpdate({}, {}, { new: true })` because `omitUndefined` will
// remove `name: undefined`
res = await Test.findOneAndUpdate({}, { $set: { name: undefined } }, { new: true, omitUndefined: true });
Mongoose 5.x 支持 omitUndefined
选项来删除 undefined
键。在 Mongoose 6.x 中,omitUndefined
选项已被删除,并且 Mongoose 将始终删除未定义的键。
¥Mongoose 5.x supported an omitUndefined
option to strip out undefined
keys.
In Mongoose 6.x, the omitUndefined
option has been removed, and Mongoose will always strip out undefined keys.
// In Mongoose 6, equivalent to `findOneAndUpdate({}, {}, { new: true })` because Mongoose will
// remove `name: undefined`
const res = await Test.findOneAndUpdate({}, { $set: { name: undefined } }, { new: true });
唯一的解决方法是在更新中将属性显式设置为 null
:
¥The only workaround is to explicitly set properties to null
in your updates:
const res = await Test.findOneAndUpdate({}, { $set: { name: null } }, { new: true });
将参数记录为默认函数
¥Document Parameter to Default Functions
Mongoose 现在将文档作为第一个参数传递给 default
函数,这对于使用默认值的 箭头函数 很有帮助。
¥Mongoose now passes the document as the first parameter to default
functions, which is helpful for using arrow functions with defaults.
如果你将需要不同参数的函数传递给 default
(例如 default: mongoose.Types.ObjectId
),这可能会影响你。参见 gh-9633。如果你传递不使用文档的默认函数,请将 default: myFunction
更改为 default: () => myFunction()
以避免意外传递可能更改行为的参数。
¥This may affect you if you pass a function that expects different parameters to default
, like default: mongoose.Types.ObjectId
. See gh-9633. If you're passing a default function that does not utilize the document, change default: myFunction
to default: () => myFunction()
to avoid accidentally passing parameters that potentially change the behavior.
const schema = new Schema({
name: String,
age: Number,
canVote: {
type: Boolean,
// Default functions now receive a `doc` parameter, helpful for arrow functions
default: doc => doc.age >= 18
}
});
数组是代理
¥Arrays are Proxies
Mongoose 数组现在是 ES6 代理。直接设置数组索引后就不再需要 markModified()
了。
¥Mongoose arrays are now ES6 proxies. You no longer need to markModified()
after setting an array index directly.
const post = await BlogPost.findOne();
post.tags[0] = 'javascript';
await post.save(); // Works, no need for `markModified()`!
typePojoToMixed
使用 type: { name: String }
声明的结构路径在 Mongoose 6 中成为单个嵌套子文档,而不是 Mongoose 5 中的混合。这消除了对 typePojoToMixed
选项的需要。参见 gh-7181。
¥Schema paths declared with type: { name: String }
become single nested subdocs in Mongoose 6, as opposed to Mixed in Mongoose 5. This removes the need for the typePojoToMixed
option. See gh-7181.
// In Mongoose 6, the below makes `foo` into a subdocument with a `name` property.
// In Mongoose 5, the below would make `foo` a `Mixed` type, _unless_ you set `typePojoToMixed: false`.
const schema = new Schema({
foo: { type: { name: String } }
});
strictPopulate()
如果你 populate()
结构中未定义的路径,Mongoose 现在会抛出错误。这仅适用于我们可以推断本地模式的情况,例如当你使用 Query#populate()
时,而不是当你在 POJO 上调用 Model.populate()
时。参见 gh-5124。
¥Mongoose now throws an error if you populate()
a path that isn't defined in your schema. This is only for cases when we can infer the local schema, like when you use Query#populate()
, not when you call Model.populate()
on a POJO. See gh-5124.
子文档 ref
函数上下文
¥Subdocument ref
Function Context
当使用函数 ref
或 refPath
填充子文档时,this
现在是正在填充的子文档,而不是顶层文档。参见 #8469。
¥When populating a subdocument with a function ref
or refPath
, this
is now the subdocument being populated, not the top-level document. See #8469.
const schema = new Schema({
works: [{
modelId: String,
data: {
type: mongoose.ObjectId,
ref: function(doc) {
// In Mongoose 6, `doc` is the array element, so you can access `modelId`.
// In Mongoose 5, `doc` was the top-level document.
return doc.modelId;
}
}
}]
});
结构保留名称警告
¥Schema Reserved Names Warning
使用 save
、isNew
和其他 Mongoose 保留名称作为结构路径名现在会触发警告,而不是错误。你可以通过在结构选项中设置 suppressReservedKeysWarning
来抑制警告:new Schema({ save: String }, { suppressReservedKeysWarning: true })
。请记住,这可能会破坏依赖这些保留名称的插件。
¥Using save
, isNew
, and other Mongoose reserved names as schema path names now triggers a warning, not an error. You can suppress the warning by setting the suppressReservedKeysWarning
in your schema options: new Schema({ save: String }, { suppressReservedKeysWarning: true })
. Keep in mind that this may break plugins that rely on these reserved names.
子文档路径
¥Subdocument Paths
单个嵌套子文档已重命名为 "子文档路径"。所以 SchemaSingleNestedOptions
现在是 SchemaSubdocumentOptions
,mongoose.Schema.Types.Embedded
现在是 mongoose.Schema.Types.Subdocument
。见 gh-10419
¥Single nested subdocs have been renamed to "subdocument paths". So SchemaSingleNestedOptions
is now SchemaSubdocumentOptions
and mongoose.Schema.Types.Embedded
is now mongoose.Schema.Types.Subdocument
. See gh-10419
创建聚合游标
¥Creating Aggregation Cursors
Aggregate#cursor()
现在返回一个 AggregationCursor 实例以与 Query#cursor()
保持一致。你不再需要执行 Model.aggregate(pipeline).cursor().exec()
来获取聚合游标,只需执行 Model.aggregate(pipeline).cursor()
即可。
¥Aggregate#cursor()
now returns an AggregationCursor instance to be consistent with Query#cursor()
. You no longer need to do Model.aggregate(pipeline).cursor().exec()
to get an aggregation cursor, just Model.aggregate(pipeline).cursor()
.
autoCreate
默认为 true
¥autoCreate
Defaults to true
autoCreate
默认为 true
,除非 readPreference 为 secondary 或 secondaryPreferred,这意味着 Mongoose 将在创建索引之前尝试创建每个模型的底层集合。如果 readPreference 是 secondary 或 secondaryPreferred,Mongoose 对于 autoCreate
和 autoIndex
将默认为 false
,因为当连接到辅助时,createCollection()
和 createIndex()
都会失败。
¥autoCreate
is true
by default unless readPreference is secondary or secondaryPreferred, which means Mongoose will attempt to create every model's underlying collection before creating indexes. If readPreference is secondary or secondaryPreferred, Mongoose will default to false
for both autoCreate
and autoIndex
because both createCollection()
and createIndex()
will fail when connected to a secondary.
不再有 context: 'query'
¥No More context: 'query'
用于查询的 context
选项已被删除。现在 Mongoose 总是使用 context = 'query'
。
¥The context
option for queries has been removed. Now Mongoose always uses context = 'query'
.
具有填充路径的自定义验证器
¥Custom Validators with Populated Paths
Mongoose 6 总是使用已删除的路径(即使用 id 而不是文档本身)调用验证器。在 Mongoose 5 中,如果路径已填充,Mongoose 将使用填充的文档调用验证器。见 #8042
¥Mongoose 6 always calls validators with depopulated paths (that is, with the id rather than the document itself). In Mongoose 5, Mongoose would call validators with the populated doc if the path was populated. See #8042
与副本集断开连接的事件
¥Disconnected Event with Replica Sets
当连接到副本集时,当与主节点的连接丢失时,连接现在会发出 'disconnected'。在 Mongoose 5 中,当失去与副本集所有成员的连接时,连接仅发出 'disconnected'。
¥When connected to a replica set, connections now emit 'disconnected' when connection to the primary is lost. In Mongoose 5, connections only emitted 'disconnected' when losing connection to all members of the replica set.
但是,Mongoose 6 在连接断开时不会缓冲命令。因此,即使 Mongoose 连接处于断开状态,你仍然可以成功执行诸如使用 readPreference = 'secondary'
进行查询之类的命令。
¥However, Mongoose 6 does not buffer commands while a connection is disconnected. So you can still successfully execute commands like queries with readPreference = 'secondary'
, even if the Mongoose connection is in the disconnected state.
删除了 execPopulate()
¥Removed execPopulate()
Document#populate()
现在返回一个 promise 并且不再可链式。
¥Document#populate()
now returns a promise and is now no longer chainable.
将
await doc.populate('path1').populate('path2').execPopulate();
替换为await doc.populate(['path1', 'path2']);
¥Replace
await doc.populate('path1').populate('path2').execPopulate();
withawait doc.populate(['path1', 'path2']);
将
await doc.populate('path1', 'select1').populate('path2', 'select2').execPopulate();
替换为¥Replace
await doc.populate('path1', 'select1').populate('path2', 'select2').execPopulate();
withawait doc.populate([{path: 'path1', select: 'select1'}, {path: 'path2', select: 'select2'}]);
create()
为空数组
¥create()
with Empty Array
v6.0 中的 await Model.create([])
在提供空数组时返回空数组,在 v5.0 中它用于返回 undefined
。如果你的任何代码正在检查输出是否为 undefined
,则需要修改它并假设 await Model.create(...)
将始终返回一个数组(如果提供了数组)。
¥await Model.create([])
in v6.0 returns an empty array when provided an empty array, in v5.0 it used to return undefined
. If any of your code is checking whether the output is undefined
or not, you need to modify it with the assumption that await Model.create(...)
will always return an array if provided an array.
删除了嵌套路径合并
¥Removed Nested Path Merging
现在,无论 child
是嵌套路径还是子文档,doc.set({ child: { age: 21 } })
的工作方式都是相同的:Mongoose 会覆盖 child
的值。在 Mongoose 5 中,如果 child
是嵌套路径,则此操作将合并 child
。
¥doc.set({ child: { age: 21 } })
now works the same whether child
is a nested path or a subdocument: Mongoose will overwrite the value of child
. In Mongoose 5, this operation would merge child
if child
was a nested path.
ObjectId valueOf()
Mongoose 现在向 ObjectIds 添加了 valueOf()
函数。这意味着你现在可以使用 ==
将 ObjectId 与字符串进行比较。
¥Mongoose now adds a valueOf()
function to ObjectIds. This means you can now use ==
to compare an ObjectId against a string.
const a = ObjectId('6143b55ac9a762738b15d4f0');
a == '6143b55ac9a762738b15d4f0'; // true
不可变的 createdAt
¥Immutable createdAt
如果你设置 timestamps: true
,Mongoose 现在会将 createdAt
属性设置为 immutable
。见 gh-10139
¥If you set timestamps: true
, Mongoose will now make the createdAt
property immutable
. See gh-10139
删除了验证器 isAsync
¥Removed Validator isAsync
isAsync
不再是 validate
的选项。请改用 async function
。
¥isAsync
is no longer an option for validate
. Use an async function
instead.
删除了 safe
¥Removed safe
safe
不再是结构、查询或 save()
的选项。请改用 writeConcern
。
¥safe
is no longer an option for schemas, queries, or save()
. Use writeConcern
instead.
SchemaType set
参数
¥SchemaType set
parameters
Mongoose 现在使用 priorValue
作为第二个参数调用 setter 函数,而不是 Mongoose 5 中的 schemaType
。
¥Mongoose now calls setter functions with priorValue
as the 2nd parameter, rather than schemaType
in Mongoose 5.
const userSchema = new Schema({
name: {
type: String,
trimStart: true,
set: trimStartSetter
}
});
// in v5.x the parameters were (value, schemaType), in v6.x the parameters are (value, priorValue, schemaType).
function trimStartSetter(val, priorValue, schemaType) {
if (schemaType.options.trimStart && typeof val === 'string') {
return val.trimStart();
}
return val;
}
const User = mongoose.model('User', userSchema);
const user = new User({ name: 'Robert Martin' });
console.log(user.name); // 'robert martin'
toObject()
和 toJSON()
使用嵌套架构 minimize
¥toObject()
and toJSON()
Use Nested Schema minimize
从技术上讲,此更改是随 5.10.5 一起发布的,但 导致用户从 5.9.x 迁移到 6.x 时出现问题。在 Mongoose < 5.10.5
、toObject()
和 toJSON()
中,默认情况下将使用顶层结构的 minimize
选项。
¥This change was technically released with 5.10.5, but caused issues for users migrating from 5.9.x to 6.x.
In Mongoose < 5.10.5
, toObject()
and toJSON()
would use the top-level schema's minimize
option by default.
const child = new Schema({ thing: Schema.Types.Mixed });
const parent = new Schema({ child }, { minimize: false });
const Parent = model('Parent', parent);
const p = new Parent({ child: { thing: {} } });
// In v5.10.4, would contain `child.thing` because `toObject()` uses `parent` schema's `minimize` option
// In `>= 5.10.5`, `child.thing` is omitted because `child` schema has `minimize: true`
console.log(p.toObject());
作为解决方法,你可以显式地将 minimize
传递给 toObject()
或 toJSON()
:
¥As a workaround, you can either explicitly pass minimize
to toObject()
or toJSON()
:
console.log(p.toObject({ minimize: false }));
或者定义内联 child
结构(仅限 Mongoose 6)以继承父级的 minimize
选项。
¥Or define the child
schema inline (Mongoose 6 only) to inherit the parent's minimize
option.
const parent = new Schema({
// Implicitly creates a new schema with the top-level schema's `minimize` option.
child: { type: { thing: Schema.Types.Mixed } }
}, { minimize: false });
Query.prototype.populate()
无默认型号
¥No default model for Query.prototype.populate()
在 Mongoose 5 中,在混合类型或其他没有 ref
的路径上调用 populate()
将回退到使用查询的模型。
¥In Mongoose 5, calling populate()
on a mixed type or other path with no ref
would fall back to using the query's model.
const testSchema = new mongoose.Schema({
data: String,
parents: Array // Array of mixed
});
const Test = mongoose.model('Test', testSchema);
// The below `populate()`...
await Test.findOne().populate('parents');
// Is a shorthand for the following populate in Mongoose 5
await Test.findOne().populate({ path: 'parents', model: Test });
在 Mongoose 6 中,填充没有 ref
、refPath
或 model
的路径是无操作。
¥In Mongoose 6, populating a path with no ref
, refPath
, or model
is a no-op.
// The below `populate()` does nothing.
await Test.findOne().populate('parents');
MongoDB 驱动程序的新 URL 解析器与某些 npm 包不兼容
¥MongoDB Driver's New URL Parser Incompatible with Some npm Packages
Mongoose 6 使用的 MongoDB Node 驱动程序版本依赖于 URL 解析器模块,该 URL 解析器模块 与其他 npm 包存在多个已知的兼容性问题。如果你使用不兼容的软件包之一,这可能会导致类似 Invalid URL: mongodb+srv://username:password@development.xyz.mongodb.net/abc
的错误。你可以在此处找到不兼容的软件包列表。
¥The MongoDB Node driver version that Mongoose 6 uses relies on a URL parser module that has several known compatibility issues with other npm packages.
This can lead to errors like Invalid URL: mongodb+srv://username:password@development.xyz.mongodb.net/abc
if you use one of the incompatible packages.
You can find a list of incompatible packages here.
删除了 reconnectTries
和 reconnectInterval
选项
¥Removed reconnectTries
and reconnectInterval
options
reconnectTries
和 reconnectInterval
选项已被删除,因为它们不再需要。
¥The reconnectTries
and reconnectInterval
options have been removed since they are no longer necessary.
MongoDB Node 驱动程序将始终尝试重试任何操作,最多 serverSelectionTimeoutMS
,即使 MongoDB 长时间关闭也是如此。因此,它永远不会用完重试次数或尝试重新连接到 MongoDB。
¥The MongoDB node driver will always attempt to retry any operation for up to serverSelectionTimeoutMS
, even if MongoDB is down for a long period of time.
So, it will never run out of retries or try to reconnect to MongoDB.
Lodash .isEmpty()
对 ObjectIds 返回 true
¥Lodash .isEmpty()
returns true for ObjectIds
Lodash 的 isEmpty()
函数对原语和原语封装器返回 true。ObjectId()
是一个对象封装器,被 Mongoose 视为原语。但从 Mongoose 6 开始,由于 Lodash 实现细节,_.isEmpty()
将对 ObjectIds 返回 true。
¥Lodash's isEmpty()
function returns true for primitives and primitive wrappers.
ObjectId()
is an object wrapper that is treated as a primitive by Mongoose.
But starting in Mongoose 6, _.isEmpty()
will return true for ObjectIds because of Lodash implementation details.
mongoose 中的 ObjectId 永远不会为空,因此如果你使用 isEmpty()
,则应检查 instanceof ObjectId
。
¥An ObjectId in mongoose is never empty, so if you're using isEmpty()
you should check for instanceof ObjectId
.
if (!(val instanceof Types.ObjectId) && _.isEmpty(val)) {
// Handle empty object here
}
删除了 mongoose.modelSchemas
¥Removed mongoose.modelSchemas
mongoose.modelSchemas
属性已被删除。这可能已用于删除模型模式。
¥The mongoose.modelSchemas
property was removed. This may have been used to delete a model schema.
// before
delete mongoose.modelSchemas.User;
// with Mongoose 6.x
delete mongoose.deleteModel('User');
TypeScript 更改
¥TypeScript changes
Schema
类现在采用 3 个通用参数,而不是 4 个。第三个通用参数 SchemaDefinitionType
现在与第一个通用参数 DocType
相同。将 new Schema<UserDocument, UserModel, User>(schemaDefinition)
替换为 new Schema<UserDocument, UserModel>(schemaDefinition)
¥The Schema
class now takes 3 generic params instead of 4. The 3rd generic param, SchemaDefinitionType
, is now the same as the 1st generic param DocType
. Replace new Schema<UserDocument, UserModel, User>(schemaDefinition)
with new Schema<UserDocument, UserModel>(schemaDefinition)
Types.ObjectId
现在是一个类,这意味着使用 new mongoose.Types.ObjectId()
创建新的 ObjectId 时不能再省略 new
。目前,你仍然可以在 JavaScript 中省略 new
,但在 TypeScript 中必须放置 new
。
¥Types.ObjectId
is now a class, which means you can no longer omit new
when creating a new ObjectId using new mongoose.Types.ObjectId()
.
Currently, you can still omit new
in JavaScript, but you must put new
in TypeScript.
以下旧类型已被删除:
¥The following legacy types have been removed:
ModelUpdateOptions
DocumentQuery
HookSyncCallback
HookAsyncCallback
HookErrorCallback
HookNextFunction
HookDoneFunction
SchemaTypeOpts
ConnectionOptions
Mongoose 6 在虚拟 getter 和 setter 中推断 this
的文档类型。在 Mongoose 5.x 中,以下代码中的 this
将是 any
。
¥Mongoose 6 infers the document's type for this
in virtual getters and setters.
In Mongoose 5.x, this
would be any
in the following code.
schema.virtual('myVirtual').get(function() {
this; // any in Mongoose 5.x
});
在 Mongoose 6 中,this
将被设置为文档类型。
¥In Mongoose 6, this
will be set to the document type.
const schema = new Schema({ name: String });
schema.virtual('myVirtual').get(function() {
this.name; // string
});