Skip to content

Commit d24762d

Browse files
committed
BREAKING CHANGE: remove support for callbacks in pre middleware
Fix #11531
1 parent 10a6caa commit d24762d

25 files changed

+151
-258
lines changed

docs/migrating_to_9.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,14 @@ const { promiseOrCallback } = require('mongoose');
185185
promiseOrCallback; // undefined in Mongoose 9
186186
```
187187

188-
## In `isAsync` middleware `next()` errors take priority over `done()` errors
188+
## `isAsync` middleware no longer supported
189189

190-
Due to Mongoose middleware now relying on promises and async/await, `next()` errors take priority over `done()` errors.
191-
If you use `isAsync` middleware, any errors in `next()` will be thrown first, and `done()` errors will only be thrown if there are no `next()` errors.
190+
Mongoose 9 no longer supports `isAsync` middleware. Middleware functions that use the legacy signature with both `next` and `done` callbacks (i.e., `function(next, done)`) are not supported. We recommend middleware now use promises or async/await.
191+
192+
If you have code that uses `isAsync` middleware, you must refactor it to use async functions or return a promise instead.
192193

193194
```javascript
195+
// ❌ Not supported in Mongoose 9
194196
const schema = new Schema({});
195197

196198
schema.pre('save', true, function(next, done) {
@@ -214,8 +216,16 @@ schema.pre('save', true, function(next, done) {
214216
25);
215217
});
216218

217-
// In Mongoose 8, with the above middleware, `save()` would error with 'first done() error'
218-
// In Mongoose 9, with the above middleware, `save()` will error with 'second next() error'
219+
// ✅ Supported in Mongoose 9: use async functions or return a promise
220+
schema.pre('save', async function() {
221+
execed.first = true;
222+
await new Promise(resolve => setTimeout(resolve, 5));
223+
});
224+
225+
schema.pre('save', async function() {
226+
execed.second = true;
227+
await new Promise(resolve => setTimeout(resolve, 25));
228+
});
219229
```
220230

221231
## Removed `skipOriginalStackTraces` option

lib/helpers/timestamps/setupTimestamps.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,13 @@ module.exports = function setupTimestamps(schema, timestamps) {
4242

4343
schema.add(schemaAdditions);
4444

45-
schema.pre('save', function timestampsPreSave(next) {
45+
schema.pre('save', function timestampsPreSave() {
4646
const timestampOption = get(this, '$__.saveOptions.timestamps');
4747
if (timestampOption === false) {
48-
return next();
48+
return;
4949
}
5050

5151
setDocumentTimestamps(this, timestampOption, currentTime, createdAt, updatedAt);
52-
53-
next();
5452
});
5553

5654
schema.methods.initializeTimestamps = function() {
@@ -88,7 +86,7 @@ module.exports = function setupTimestamps(schema, timestamps) {
8886
schema.pre('updateOne', opts, _setTimestampsOnUpdate);
8987
schema.pre('updateMany', opts, _setTimestampsOnUpdate);
9088

91-
function _setTimestampsOnUpdate(next) {
89+
function _setTimestampsOnUpdate() {
9290
const now = currentTime != null ?
9391
currentTime() :
9492
this.model.base.now();
@@ -105,6 +103,5 @@ module.exports = function setupTimestamps(schema, timestamps) {
105103
replaceOps.has(this.op)
106104
);
107105
applyTimestampsToChildren(now, this.getUpdate(), this.model.schema);
108-
next();
109106
}
110107
};

lib/model.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2914,7 +2914,6 @@ Model.insertMany = async function insertMany(arr, options) {
29142914
await this._middleware.execPost('insertMany', this, [arr], { error });
29152915
}
29162916

2917-
29182917
options = options || {};
29192918
const ThisModel = this;
29202919
const limit = options.limit || 1000;

lib/plugins/validateBeforeSave.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
module.exports = function validateBeforeSave(schema) {
88
const unshift = true;
9-
schema.pre('save', false, async function validateBeforeSave(_next, options) {
9+
schema.pre('save', false, async function validateBeforeSave(options) {
1010
// Nested docs have their own presave
1111
if (this.$isSubdocument) {
1212
return;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"type": "commonjs",
2121
"license": "MIT",
2222
"dependencies": {
23-
"kareem": "git+https://github.com/mongoosejs/kareem.git#vkarpov15/v3",
23+
"kareem": "git+https://github.com/mongoosejs/kareem.git#vkarpov15/remove-isasync",
2424
"mongodb": "~6.18.0",
2525
"mpath": "0.9.0",
2626
"mquery": "5.0.0",

test/aggregate.test.js

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -886,9 +886,9 @@ describe('aggregate: ', function() {
886886
const s = new Schema({ name: String });
887887

888888
let called = 0;
889-
s.pre('aggregate', function(next) {
889+
s.pre('aggregate', function() {
890890
++called;
891-
next();
891+
return Promise.resolve();
892892
});
893893

894894
const M = db.model('Test', s);
@@ -902,9 +902,9 @@ describe('aggregate: ', function() {
902902
it('setting option in pre (gh-7606)', async function() {
903903
const s = new Schema({ name: String });
904904

905-
s.pre('aggregate', function(next) {
905+
s.pre('aggregate', function() {
906906
this.options.collation = { locale: 'en_US', strength: 1 };
907-
next();
907+
return Promise.resolve();
908908
});
909909

910910
const M = db.model('Test', s);
@@ -920,9 +920,9 @@ describe('aggregate: ', function() {
920920
it('adding to pipeline in pre (gh-8017)', async function() {
921921
const s = new Schema({ name: String });
922922

923-
s.pre('aggregate', function(next) {
923+
s.pre('aggregate', function() {
924924
this.append({ $limit: 1 });
925-
next();
925+
return Promise.resolve();
926926
});
927927

928928
const M = db.model('Test', s);
@@ -980,8 +980,8 @@ describe('aggregate: ', function() {
980980
const s = new Schema({ name: String });
981981

982982
const calledWith = [];
983-
s.pre('aggregate', function(next) {
984-
next(new Error('woops'));
983+
s.pre('aggregate', function() {
984+
return Promise.reject(new Error('woops'));
985985
});
986986
s.post('aggregate', function(error, res, next) {
987987
calledWith.push(error);
@@ -1003,9 +1003,9 @@ describe('aggregate: ', function() {
10031003

10041004
let calledPre = 0;
10051005
let calledPost = 0;
1006-
s.pre('aggregate', function(next) {
1006+
s.pre('aggregate', function() {
10071007
++calledPre;
1008-
next();
1008+
return Promise.resolve();
10091009
});
10101010
s.post('aggregate', function(res, next) {
10111011
++calledPost;
@@ -1030,9 +1030,9 @@ describe('aggregate: ', function() {
10301030

10311031
let calledPre = 0;
10321032
const calledPost = [];
1033-
s.pre('aggregate', function(next) {
1033+
s.pre('aggregate', function() {
10341034
++calledPre;
1035-
next();
1035+
return Promise.resolve();
10361036
});
10371037
s.post('aggregate', function(res, next) {
10381038
calledPost.push(res);
@@ -1295,11 +1295,10 @@ describe('aggregate: ', function() {
12951295
it('cursor() errors out if schema pre aggregate hook throws an error (gh-15279)', async function() {
12961296
const schema = new Schema({ name: String });
12971297

1298-
schema.pre('aggregate', function(next) {
1298+
schema.pre('aggregate', function() {
12991299
if (!this.options.allowed) {
13001300
throw new Error('Unauthorized aggregate operation: only allowed operations are permitted');
13011301
}
1302-
next();
13031302
});
13041303

13051304
const Test = db.model('Test', schema);

test/docs/discriminators.test.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,15 @@ describe('discriminator docs', function() {
164164

165165
const eventSchema = new mongoose.Schema({ time: Date }, options);
166166
let eventSchemaCalls = 0;
167-
eventSchema.pre('validate', function(next) {
167+
eventSchema.pre('validate', function() {
168168
++eventSchemaCalls;
169-
next();
170169
});
171170
const Event = mongoose.model('GenericEvent', eventSchema);
172171

173172
const clickedLinkSchema = new mongoose.Schema({ url: String }, options);
174173
let clickedSchemaCalls = 0;
175-
clickedLinkSchema.pre('validate', function(next) {
174+
clickedLinkSchema.pre('validate', function() {
176175
++clickedSchemaCalls;
177-
next();
178176
});
179177
const ClickedLinkEvent = Event.discriminator('ClickedLinkEvent',
180178
clickedLinkSchema);

test/document.modified.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,8 @@ describe('document modified', function() {
323323
});
324324

325325
let preCalls = 0;
326-
childSchema.pre('save', function(next) {
326+
childSchema.pre('save', function() {
327327
++preCalls;
328-
next();
329328
});
330329

331330
let postCalls = 0;

0 commit comments

Comments
 (0)