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.exec
Aggregate.prototype.explain
AggregationCursor.prototype.close
AggregationCursor.prototype.next
AggregationCursor.prototype.eachAsync
Connection.prototype.startSession
Connection.prototype.dropCollection
Connection.prototype.createCollection
Connection.prototype.dropDatabase
Connection.prototype.openUri
Connection.prototype.close
Connection.prototype.destroy
Document.prototype.populate
Document.prototype.validate
Mongoose.prototype.connect
Mongoose.prototype.createConnection
Model.prototype.save
Model.aggregate
Model.bulkWrite
Model.cleanIndexes
Model.countDocuments
Model.create
Model.createCollection
Model.createIndexes
Model.deleteOne
Model.deleteMany
Model.distinct
Model.ensureIndexes
Model.estimatedDocumentCount
Model.exists
Model.find
Model.findById
Model.findByIdAndUpdate
Model.findByIdAndReplace
Model.findOne
Model.findOneAndDelete
Model.findOneAndUpdate
Model.findOneAndRemove
Model.insertMany
Model.listIndexes
Model.replaceOne
Model.syncIndexes
Model.updateMany
Model.updateOne
Query.prototype.find
Query.prototype.findOne
Query.prototype.findOneAndDelete
Query.prototype.findOneAndUpdate
Query.prototype.findOneAndRemove
Query.prototype.findOneAndReplace
Query.prototype.validate
Query.prototype.deleteOne
Query.prototype.deleteMany
Query.prototype.exec
QueryCursor.prototype.close
QueryCursor.prototype.next
QueryCursor.prototype.eachAsync
上記の関数をコールバックで使用している場合は、async/awaitに切り替えることをお勧めします。async関数が使用できない場合は、Promiseを使用してください。レガシーコードベースのリファクタリングに支援が必要な場合は、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以前では、new
キーワードを使用せずに新しいObjectIdを定義できました。
// 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')
これは、obj
にid
と_id
の両方が含まれているnew TestModel(obj)
を作成する場合、または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は、SchemaTypeのcastForQuery()
メソッドを常に3つの引数($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 6の`'ObjectID'`とは異なり、Mongoose 7では`'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でBluebird Promiseが返されることはなくなりました。
const mongoose = require('mongoose');
// No-op on Mongoose 7
mongoose.Promise = require('bluebird');
すべてのPromiseにグローバルにBluebirdを使用する場合は、次のようにします。
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では、最初のパラメータは生のドキュメントインターフェース、2番目のパラメータはドキュメント固有のオーバーライド(通常は仮想とメソッド)、3番目のパラメータはドキュメントのモデルに関連付けられたクエリヘルパーです。
主な違いは、Mongoose 6では3番目のジェネリックパラメータがドキュメントの_仮想_であったのに対し、Mongoose 7では3番目のジェネリックパラメータがドキュメントの_クエリヘルパー_であることです。
// Mongoose 6 version:
type UserDocument = HydratedDocument<TUser, TUserMethods, TUserVirtuals>;
// Mongoose 7:
type UserDocument = HydratedDocument<TUser, TUserMethods & TUserVirtuals, TUserQueryHelpers>;