5.xから6.xへの移行
注意: Mongoose 5のサポートは2024年3月1日に終了する予定です。詳細については、バージョンサポートガイドをご覧ください。
Mongoose 5.xからMongoose 6.xに移行する際には、いくつかの後方互換性のない変更に注意する必要があります。
Mongoose 4.xをまだ使用している場合は、Mongoose 4.xから5.xへの移行ガイドを読み、まずMongoose 5.xにアップグレードしてください。
- バージョン要件
- MongoDB Driver 4.0
- 非推奨警告オプションの廃止
- 接続の
asPromise()
メソッド mongoose.connect()
はPromiseを返す- クエリの重複実行
Model.exists()
はBooleanではなくリーンなドキュメントを返すstrictQuery
はデフォルトでstrict
と同等になった- MongoErrorはMongoServerErrorになった
isValidObjectId()
の簡略化とisObjectIdOrHexString()
の分離- デフォルトで判別子スキーマをクローンする
- スキーマで定義されたドキュメントキーの順序
sanitizeFilter
とtrusted()
omitUndefined
の削除: Mongooseは、undefined
キーをnull
に設定するのではなく、更新時に削除するようになった- デフォルト関数へのドキュメントパラメータ
- 配列はプロキシ
typePojoToMixed
strictPopulate()
- サブドキュメント
ref
関数のコンテキスト - スキーマの予約名に関する警告
- サブドキュメントパス
- アグリゲーションカーソルの作成
autoCreate
はデフォルトでtrue
context: 'query'
の廃止- ポピュレートされたパスを持つカスタムバリデーター
- レプリカセットでの切断イベント
execPopulate()
の削除- 空の配列での
create()
- ネストされたパスのマージの削除
- ObjectId
valueOf()
- イミュータブルな
createdAt
- バリデーター
isAsync
の削除 safe
の削除- SchemaTypeの
set
パラメータは、self
の代わりに2番目のパラメータとしてpriorValue
を使用するようになった Query.prototype.populate()
のデフォルトモデルの廃止toObject()
とtoJSON()
はネストされたスキーマのminimize
を使用する- TypeScriptの変更
reconnectTries
およびreconnectInterval
オプションの削除- MongoDB Driverの新しいURLパーサーは、一部のnpmパッケージと互換性がない
バージョン要件
MongooseはNode.js >= 12.0.0を必要とするようになりました。Mongooseは、MongoDBサーバーのバージョン3.0.0までをサポートしています。
MongoDB Driver 4.0
Mongooseは、MongoDB Node driverのv4.xを使用するようになりました。詳細については、MongoDB Node driversの移行ガイドを参照してください。以下は、最も注目すべき変更点の一部です。
- MongoDB Driver 4.xはTypeScriptで記述されており、独自のTypeScript型定義があります。これらは
@types/mongodb
と競合する可能性があるため、TypeScriptコンパイラエラーが発生した場合は、最新バージョンの@types/mongodb
(空のスタブ)にアップグレードしてください。 - 接続の
poolSize
オプションは、minPoolSize
とmaxPoolSize
に置き換えられました。Mongoose 5.xのpoolSize
オプションは、Mongoose 6のmaxPoolSize
オプションと同等です。maxPoolSize
のデフォルト値は100に増加しました。 updateOne()
およびupdateMany()
の結果が異なるようになりました。deleteOne()
およびdeleteMany()
の結果には、n
プロパティがなくなりました。
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`
非推奨警告オプションの廃止
useNewUrlParser
、useUnifiedTopology
、useFindAndModify
、およびuseCreateIndex
はサポートされなくなったオプションです。Mongoose 6は常にuseNewUrlParser
、useUnifiedTopology
、およびuseCreateIndex
がtrue
、useFindAndModify
がfalse
であるかのように動作します。これらのオプションをコードから削除してください。
// 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()
メソッド
Mongoose接続はもはやthenableではありません。つまり、await mongoose.createConnection(uri)
はMongooseが接続するのを待たなくなりました。代わりにmongoose.createConnection(uri).asPromise()
を使用してください。 #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()
関数は、Mongooseインスタンスではなく、常にpromiseを返すようになりました。
クエリの重複実行
Mongooseは、同じクエリオブジェクトを2回実行することを許可しなくなりました。実行すると、Query was already executed
エラーが表示されます。同じクエリインスタンスを2回実行することは、通常、コールバックとpromiseを混在させていることを示していますが、同じクエリを2回実行する必要がある場合は、Query#clone()
を呼び出してクエリを複製し、再実行できます。 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(...)
は、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
と同等になった
Mongooseは、Mongoose 6.0.10では、strictQuery
オプションをサポートしなくなりました。strict
を使用する必要があります。strictQuery
オプションが復活しました。ただし、strictQuery
はデフォルトでstrict
に結び付けられています。つまり、デフォルトでは、Mongooseはスキーマにないクエリフィルタープロパティをフィルタリングします。
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
を無効にして上書きすることもできます
mongoose.set('strictQuery', false);
MongoErrorはMongoServerErrorになった
MongoDB Node.js Driver v4.xでは、「MongoError」は「MongoServerError」になりました。ハードコードされた文字列「MongoError」に依存するコードを変更してください。
デフォルトで判別子スキーマをクローンする
Mongooseは、デフォルトで判別子スキーマを複製するようになりました。つまり、再帰的な埋め込み判別子を使用している場合は、discriminator()
に{ clone: false }
を渡す必要があります。
// 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()
の分離
Mongoose 5では、mongoose.isValidObjectId()
は数値などの値に対してfalse
を返していましたが、これはMongoDBドライバーのObjectId.isValid()
関数と矛盾していました。技術的には、任意のJavaScript数をMongoDB ObjectIdに変換できます。
Mongoose 6では、mongoose.isValidObjectId()
は、一貫性のためにmongoose.Types.ObjectId.isValid()
のラッパーにすぎません。
Mongoose 6.2.5には、isValidObjectId()
のより一般的なユースケースをより適切に捉えるmongoose.isObjectIdOrHexString()
関数が含まれるようになりました。指定された値は、ObjectId
インスタンスまたはObjectId
を表す24文字の16進文字列ですか?
// `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
スキーマで定義されたドキュメントキーの順序
Mongooseは、ユーザー定義のオブジェクトではなく、スキーマで指定されたキーの順序でキーを持つオブジェクトを保存するようになりました。したがって、Object.keys(new User({ name: String, email: String }).toObject()
が['name', 'email']
か['email', 'name']
かは、スキーマでname
とemail
が定義されている順序によって異なります。
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()
Mongoose 6には、クエリセレクターインジェクション攻撃から保護するための、グローバルおよびクエリへの新しいsanitizeFilter
オプションが導入されています。sanitizeFilter
を有効にすると、Mongooseはクエリフィルター内の任意のオブジェクトを$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()
を使用します
// `mongoose.trusted()` allows query selectors through
await Test.find({ username: 'val', pwd: mongoose.trusted({ $ne: null }) }).setOptions({ sanitizeFilter: true });
omitUndefined
の削除: Mongooseは、undefined
キーをnull
に設定するのではなく、更新時に削除するようになった
Mongoose 5.xでは、更新操作でキーをundefined
に設定することは、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は、undefined
キーを削除するためのomitUndefined
オプションをサポートしていました。Mongoose 6.xでは、omitUndefined
オプションは削除され、Mongooseは常にundefinedキーを削除するようになりました。
// 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
に設定することです
const res = await Test.findOneAndUpdate({}, { $set: { name: null } }, { new: true });
デフォルト関数へのドキュメントパラメータ
Mongooseは、アロー関数をデフォルトで使用するのに役立つ、ドキュメントを最初のパラメータとしてdefault
関数に渡すようになりました。
これは、default: mongoose.Types.ObjectId
のように、異なるパラメータを期待する関数をdefault
に渡す場合に影響を与える可能性があります。gh-9633を参照してください。ドキュメントを使用**しない**デフォルト関数を渡している場合は、誤って動作を変更する可能性のあるパラメータを渡さないように、default: myFunction
をdefault: () => myFunction()
に変更します。
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
}
});
配列はプロキシ
Mongoose配列はES6プロキシになりました。配列インデックスを直接設定した後、markModified()
する必要はなくなりました。
const post = await BlogPost.findOne();
post.tags[0] = 'javascript';
await post.save(); // Works, no need for `markModified()`!
typePojoToMixed
type: { name: String }
で宣言されたスキーマパスは、Mongoose 5のMixedではなく、Mongoose 6では単一のネストされたサブドキュメントになります。これにより、typePojoToMixed
オプションが不要になります。 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を参照してください。
サブドキュメントref
関数のコンテキスト
関数ref
またはrefPath
を使用してサブドキュメントをポピュレートする場合、this
はトップレベルのドキュメントではなく、ポピュレートされているサブドキュメントになりました。 #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;
}
}
}]
});
スキーマの予約名に関する警告
save
、isNew
、およびその他のMongoose予約名をスキーマパス名として使用すると、エラーではなく警告がトリガーされるようになりました。スキーマオプションでsuppressReservedKeysWarning
を設定することにより、警告を抑制できます。例:new Schema({ save: String }, { suppressReservedKeysWarning: true })
。これは、これらの予約名に依存するプラグインを壊す可能性があることに注意してください。
サブドキュメントパス
単一のネストされたサブドキュメントは、「サブドキュメントパス」に名前が変更されました。したがって、SchemaSingleNestedOptions
はSchemaSubdocumentOptions
になり、mongoose.Schema.Types.Embedded
はmongoose.Schema.Types.Subdocument
になります。 gh-10419を参照してください
アグリゲーションカーソルの作成
Aggregate#cursor()
は、Query#cursor()
との一貫性を保つために、AggregationCursorインスタンスを返すようになりました。アグリゲーションカーソルを取得するために、Model.aggregate(pipeline).cursor().exec()
を実行する必要はなくなり、Model.aggregate(pipeline).cursor()
だけで実行できます。
autoCreate
はデフォルトでtrue
readPreference
がsecondaryまたはsecondaryPreferredでない限り、autoCreate
はデフォルトでtrue
です。これは、Mongooseがインデックスを作成する前にすべてのモデルの基礎となるコレクションを作成しようとすることを意味します。readPreference
がsecondaryまたはsecondaryPreferredの場合、MongooseはautoCreate
とautoIndex
の両方をデフォルトでfalse
にします。これは、createCollection()
とcreateIndex()
の両方がセカンダリに接続されたときに失敗するためです。
context: 'query'
の廃止
クエリのcontext
オプションは削除されました。現在、Mongooseは常にcontext = 'query'
を使用します。
ポピュレートされたパスを持つカスタムバリデーター
Mongoose 6は、常に(ドキュメント自体ではなく、idで)デポピュレートされたパスでバリデーターを呼び出します。Mongoose 5では、パスがポピュレートされている場合、Mongooseはポピュレートされたドキュメントでバリデーターを呼び出していました。 #8042を参照してください
レプリカセットでの切断イベント
レプリカセットに接続されている場合、プライマリへの接続が失われると、接続は「disconnected」を発生させるようになりました。Mongoose 5では、接続はレプリカセットのすべてのメンバーへの接続が失われた場合にのみ「disconnected」を発生させていました。
ただし、Mongoose 6は、接続が切断されている間、コマンドをバッファリング**しません**。したがって、Mongoose接続が切断された状態にあっても、readPreference = 'secondary'
でクエリなどのコマンドを正常に実行できます。
execPopulate()
の削除
Document#populate()
はpromiseを返すようになり、チェーンできなくなりました。
await doc.populate('path1').populate('path2').execPopulate();
をawait doc.populate(['path1', 'path2']);
に置き換えてくださいawait doc.populate('path1', 'select1').populate('path2', 'select2').execPopulate();
を以下に置き換えてくださいawait doc.populate([{path: 'path1', select: 'select1'}, {path: 'path2', select: 'select2'}]);
空の配列でのcreate()
v6.0のawait Model.create([])
は、空の配列が指定されると空の配列を返しますが、v5.0ではundefined
を返していました。コードのいずれかで、出力がundefined
かどうかを確認している場合は、await Model.create(...)
が配列が指定されると常に配列を返すという前提で変更する必要があります。
ネストされたパスのマージの削除
doc.set({ child: { age: 21 } })
の動作が、child
がネストされたパスであろうとサブドキュメントであろうと、同じになりました。Mongoose は child
の値を上書きします。Mongoose 5 では、child
がネストされたパスの場合、この操作は child
をマージしていました。
ObjectId valueOf()
Mongoose は ObjectId に valueOf()
関数を追加しました。これにより、ObjectId を文字列と ==
で比較できるようになりました。
const a = ObjectId('6143b55ac9a762738b15d4f0');
a == '6143b55ac9a762738b15d4f0'; // true
イミュータブルなcreatedAt
timestamps: true
を設定した場合、Mongoose は createdAt
プロパティを immutable
にします。詳細は gh-10139 を参照してください。
バリデーターisAsync
の削除
isAsync
は validate
のオプションではなくなりました。代わりに async function
を使用してください。
safe
の削除
safe
はスキーマ、クエリ、save()
のオプションではなくなりました。代わりに writeConcern
を使用してください。
SchemaType の set
パラメータ
Mongoose は、セッター関数を呼び出す際に、Mongoose 5 の schemaType
ではなく、2番目のパラメータとして priorValue
を渡すようになりました。
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
を使用する
この変更は技術的には 5.10.5 でリリースされましたが、5.9.x から 6.x に移行するユーザーに問題を引き起こしました。Mongoose < 5.10.5
では、toObject()
と toJSON()
はデフォルトでトップレベルのスキーマの minimize
オプションを使用していました。
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()
に渡すことができます。
console.log(p.toObject({ minimize: false }));
または、親の minimize
オプションを継承するために、child
スキーマをインラインで定義する (Mongoose 6 のみ) こともできます。
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()
のデフォルトモデルの廃止
Mongoose 5 では、ref
がない混合型または他のパスで populate()
を呼び出すと、クエリのモデルを使用するようにフォールバックしていました。
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
がないパスを populate すると、何も行われません。
// The below `populate()` does nothing.
await Test.findOne().populate('parents');
MongoDB Driverの新しいURLパーサーは、一部のnpmパッケージと互換性がない
Mongoose 6 が使用する MongoDB Node ドライバーのバージョンは、他の npm パッケージとの互換性問題がいくつか知られている URLパーサーモジュール に依存しています。これにより、互換性のないパッケージのいずれかを使用すると、Invalid URL: mongodb+srv://username:password@development.xyz.mongodb.net/abc
のようなエラーが発生する可能性があります。非互換パッケージの一覧はこちらで確認できます。
TypeScriptの変更
Schema
クラスは、4つではなく3つのジェネリックパラメータを受け取るようになりました。3番目のジェネリックパラメータである SchemaDefinitionType
は、最初のジェネリックパラメータである DocType
と同じになりました。new Schema<UserDocument, UserModel, User>(schemaDefinition)
を new Schema<UserDocument, UserModel>(schemaDefinition)
に置き換えてください。
Types.ObjectId
はクラスになったため、new mongoose.Types.ObjectId()
を使用して新しい ObjectId を作成するときに new
を省略できなくなりました。現在、JavaScript では new
を省略できますが、TypeScript では 必ず new
を記述する必要があります。
以下のレガシー型は削除されました。
ModelUpdateOptions
DocumentQuery
HookSyncCallback
HookAsyncCallback
HookErrorCallback
HookNextFunction
HookDoneFunction
SchemaTypeOpts
ConnectionOptions
Mongoose 6 は、仮想ゲッターとセッターの this
にドキュメントの型を推論します。Mongoose 5.x では、以下のコードで this
は any
でした。
schema.virtual('myVirtual').get(function() {
this; // any in Mongoose 5.x
});
Mongoose 6 では、this
はドキュメントの型に設定されます。
const schema = new Schema({ name: String });
schema.virtual('myVirtual').get(function() {
this.name; // string
});
reconnectTries
およびreconnectInterval
オプションの削除
reconnectTries
および reconnectInterval
オプションは、もはや必要ないため削除されました。
MongoDB ノードドライバーは、MongoDB が長期間ダウンしている場合でも、serverSelectionTimeoutMS
まで常に操作を再試行します。そのため、再試行がなくなることや MongoDB に再接続しようとすることはありません。