从 6.x 迁移到 7.x
从 Mongoose 6.x 迁移到 Mongoose 7.x 时,您应该注意一些向后不兼容的更改。
如果您仍然使用 Mongoose 5.x,请阅读 Mongoose 5.x 到 6.x 迁移指南 并在升级到 Mongoose 6.x 后再进行操作。
strictQuery- 移除
remove() - 删除回调支持
- 移除
update() - ObjectId 需要
new id设置器- 鉴别器模式默认使用基本模式选项
- 移除
castForQueryWrapper(),更新castForQuery()签名 - 在
Schema.prototype.add()中复制模式选项 - ObjectId bsontype 现在使用小写 d
- 删除对自定义 Promise 库的支持
- 删除 mapReduce
- TypeScript 特定更改
strictQuery
strictQuery 现在默认为 false。
const mySchema = new Schema({ field: Number });
const MyModel = mongoose.model('Test', mySchema);
// Mongoose will not strip out `notInSchema: 1` because `strictQuery` is false by default
const docs = await MyModel.find({ notInSchema: 1 });
// Empty array in Mongoose 7. In Mongoose 6, this would contain all documents in MyModel
docs;
移除 remove()
文档和模型上的 remove() 方法已被移除。请改用 deleteOne() 或 deleteMany()。
const mySchema = new Schema({ field: Number });
const MyModel = mongoose.model('Test', mySchema);
// Change this:
await MyModel.remove(filter);
// To this:
await MyModel.deleteOne(filter);
// Or this, if you want to delete multiple:
await MyModel.deleteMany(filter);
// For documents, change this:
await doc.remove();
// To this:
await doc.deleteOne();请记住,deleteOne() 钩子默认被视为查询中间件。因此,对于中间件,请执行以下操作
// Replace this:
schema.pre('remove', function() {
/* ... */
});
// With this:
schema.pre('deleteOne', { document: true, query: false }, function() {
/* ... */
});删除回调支持
以下函数不再接受回调。它们始终返回 Promise。
Aggregate.prototype.execAggregate.prototype.explainAggregationCursor.prototype.closeAggregationCursor.prototype.nextAggregationCursor.prototype.eachAsyncConnection.prototype.startSessionConnection.prototype.dropCollectionConnection.prototype.createCollectionConnection.prototype.dropDatabaseConnection.prototype.openUriConnection.prototype.closeConnection.prototype.destroyDocument.prototype.populateDocument.prototype.validateMongoose.prototype.connectMongoose.prototype.createConnectionModel.prototype.saveModel.aggregateModel.bulkWriteModel.cleanIndexesModel.countDocumentsModel.createModel.createCollectionModel.createIndexesModel.deleteOneModel.deleteManyModel.distinctModel.ensureIndexesModel.estimatedDocumentCountModel.existsModel.findModel.findByIdModel.findByIdAndUpdateModel.findByIdAndReplaceModel.findOneModel.findOneAndDeleteModel.findOneAndUpdateModel.findOneAndRemoveModel.insertManyModel.listIndexesModel.replaceOneModel.syncIndexesModel.updateManyModel.updateOneQuery.prototype.findQuery.prototype.findOneQuery.prototype.findOneAndDeleteQuery.prototype.findOneAndUpdateQuery.prototype.findOneAndRemoveQuery.prototype.findOneAndReplaceQuery.prototype.validateQuery.prototype.deleteOneQuery.prototype.deleteManyQuery.prototype.execQueryCursor.prototype.closeQueryCursor.prototype.nextQueryCursor.prototype.eachAsync
如果您使用回调来使用上述函数,我们建议您切换到 async/await 或 Promise(如果 async 函数不适合您)。如果您需要帮助重构遗留代码库,请使用 ChatGPT 从 Mastering JS 回调到 async await 的此工具。
// Before
conn.startSession(function(err, session) {
// ...
});
// After
const session = await conn.startSession();
// Or:
conn.startSession().then(sesson => { /* ... */ });
// With error handling
try {
await conn.startSession();
} catch (err) { /* ... */ }
// Or:
const [err, session] = await conn.startSession().then(
session => ([null, session]),
err => ([err, null])
);
移除 update()
Model.update()、Query.prototype.update() 和 Document.prototype.update() 已被移除。请改用 updateOne()。
// Before
await Model.update(filter, update);
await doc.update(update);
// After
await Model.updateOne(filter, update);
await doc.updateOne(update);
ObjectId 需要 new
在 Mongoose 6 和更早版本中,您可以定义一个新的 ObjectId,而无需使用 new 关键字
// Works in Mongoose 6
// Throws "Class constructor ObjectId cannot be invoked without 'new'" in Mongoose 7
const oid = mongoose.Types.ObjectId('0'.repeat(24));在 Mongoose 7 中,ObjectId 现在是一个 JavaScript 类,因此您需要使用 new 关键字。
// Works in Mongoose 6 and Mongoose 7
const oid = new mongoose.Types.ObjectId('0'.repeat(24));
id 设置器
从 Mongoose 7.4 开始,Mongoose 的内置 id 虚拟(将文档的 _id 存储为字符串)有一个设置器,它允许通过 id 修改文档的 _id 属性。
const doc = await TestModel.findOne();
doc.id = '000000000000000000000000';
doc._id; // ObjectId('000000000000000000000000')如果您创建 new TestModel(obj),其中 obj 包含 id 和 _id,或者如果您使用 doc.set(),这会导致意想不到的行为。
// Because `id` is after `_id`, the `id` will overwrite the `_id`
const doc = new TestModel({
_id: '000000000000000000000000',
id: '111111111111111111111111'
});
doc._id; // ObjectId('111111111111111111111111')id 设置器在 Mongoose 8 中被移除,原因是兼容性问题。
鉴别器模式默认使用基本模式选项
当您使用 Model.discriminator() 时,Mongoose 现在默认将使用鉴别器基本模式的选项。这意味着您无需显式设置子模式选项以匹配基本模式的选项。
const baseSchema = Schema({}, { typeKey: '$type' });
const Base = db.model('Base', baseSchema);
// In Mongoose 6.x, the `Base.discriminator()` call would throw because
// no `typeKey` option. In Mongoose 7, Mongoose uses the base schema's
// `typeKey` by default.
const childSchema = new Schema({}, {});
const Test = Base.discriminator('Child', childSchema);
Test.schema.options.typeKey; // '$type'
移除 castForQueryWrapper,更新 castForQuery() 签名
Mongoose 现在始终使用 3 个参数调用 SchemaType castForQuery() 方法:$conditional、value 和 context。如果您已实现一个自定义模式类型,它定义了自己的 castForQuery() 方法,则需要按如下方式更新该方法。
// Mongoose 6.x format:
MySchemaType.prototype.castForQuery = function($conditional, value) {
if (arguments.length === 2) {
// Handle casting value with `$conditional` - $eq, $in, $not, etc.
} else {
value = $conditional;
// Handle casting `value` with no conditional
}
};
// Mongoose 7.x format
MySchemaType.prototype.castForQuery = function($conditional, value, context) {
if ($conditional != null) {
// Handle casting value with `$conditional` - $eq, $in, $not, etc.
} else {
// Handle casting `value` with no conditional
}
};
在 Schema.prototype.add() 中复制模式选项
Mongoose 现在在将一个模式添加到另一个模式时复制用户定义的模式选项。例如,下面的 childSchema 将获得 baseSchema 的 id 和 toJSON 选项。
const baseSchema = new Schema({ created: Date }, { id: true, toJSON: { virtuals: true } });
const childSchema = new Schema([baseSchema, { name: String }]);
childSchema.options.toJSON; // { virtuals: true } in Mongoose 7. undefined in Mongoose 6.这适用于使用模式数组创建新模式以及调用 add() 的情况,如下所示。
childSchema.add(new Schema({}, { toObject: { virtuals: true } }));
childSchema.options.toObject; // { virtuals: true } in Mongoose 7. undefined in Mongoose 6.ObjectId bsontype 现在使用小写 d
ObjectId 上的内部 _bsontype 属性在 Mongoose 7 中等于 'ObjectId',而在 Mongoose 6 中等于 'ObjectID'。
const oid = new mongoose.Types.ObjectId();
oid._bsontype; // 'ObjectId' in Mongoose 7, 'ObjectID' in older versions of Mongoose请更新任何您使用 _bsontype 来检查对象是否是 ObjectId 的地方。这也会影响使用 Mongoose 的库。
删除 mapReduce
MongoDB 不再支持 mapReduce,因此 Mongoose 7 不再具有 Model.mapReduce() 函数。请使用聚合框架替换 mapReduce()。
// The following no longer works in Mongoose 7.
const o = {
map: function() {
emit(this.author, 1);
},
reduce: function(k, vals) {
return vals.length;
}
};
await MR.mapReduce(o);删除对自定义 Promise 库的支持
Mongoose 7 不再支持插入自定义 Promise 库。因此,以下操作在 Mongoose 7 中不再使 Mongoose 返回 Bluebird Promise。
const mongoose = require('mongoose');
// No-op on Mongoose 7
mongoose.Promise = require('bluebird');如果您想全局使用 Bluebird 作为所有 Promise,您可以执行以下操作
global.Promise = require('bluebird');TypeScript 特定更改
删除 LeanDocument 和对 extends Document 的支持
Mongoose 7 不再导出 LeanDocument 类型,也不再支持将 extends Document 的文档类型传递到 Model<> 中。
// No longer supported
interface ITest extends Document {
name?: string;
}
const Test = model<ITest>('Test', schema);
// Do this instead, no `extends Document`
interface ITest {
name?: string;
}
const Test = model<ITest>('Test', schema);
// If you need to access the hydrated document type, use the following code
type TestDocument = ReturnType<(typeof Test)['hydrate']>;
HydratedDocument 的新参数
Mongoose 的 HydratedDocument 类型将原始文档接口转换为已水化的 Mongoose 文档的类型,包括虚拟、方法等。在 Mongoose 7 中,HydratedDocument 的泛型参数已更改。在 Mongoose 6 中,泛型参数为
type HydratedDocument<
DocType,
TMethodsAndOverrides = {},
TVirtuals = {}
> = Document<unknown, any, DocType> &
Require_id<DocType> &
TMethodsAndOverrides &
TVirtuals;在 Mongoose 7 中,新的类型如下所示。
type HydratedDocument<
DocType,
TOverrides = {},
TQueryHelpers = {}
> = Document<unknown, TQueryHelpers, DocType> &
Require_id<DocType> &
TOverrides;在 Mongoose 7 中,第一个参数是原始文档接口,第二个参数是任何文档特定覆盖(通常是虚拟和方法),第三个参数是与文档模型关联的任何查询帮助程序。
关键区别在于,在 Mongoose 6 中,第三个泛型参数是文档的虚拟。在 Mongoose 7 中,第三个泛型参数是文档的查询帮助程序。
// Mongoose 6 version:
type UserDocument = HydratedDocument<TUser, TUserMethods, TUserVirtuals>;
// Mongoose 7:
type UserDocument = HydratedDocument<TUser, TUserMethods & TUserVirtuals, TUserQueryHelpers>;
