Skip to content

Commit 7299980

Browse files
committed
Merge branch 'master' into 8.1
2 parents b3ef1d8 + aa4b38a commit 7299980

33 files changed

+395
-160
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
8.0.3 / 2023-12-07
2+
==================
3+
* fix(schema): avoid creating unnecessary clone of schematype in nested array so nested document arrays use correct constructor #14128 #14101
4+
* docs(connections): add example of registering connection event handlers #14150
5+
* docs(populate): add example of using `refPath` and `ref` functions #14133 #13834
6+
* types: handle using BigInt global class in schema definitions #14160 #14147
7+
* types: make findOneAndDelete() without options return result doc, not ModifyResult #14153 #14130
8+
* types(model): add no-generic override for insertMany() with options #14152 #13999
9+
* types: add missing Type for applyDefaults #14159 [jaypea](https://github.com/jaypea)
10+
11+
7.6.7 / 2023-12-06
12+
==================
13+
* fix: avoid minimizing single nested subdocs if they are required #14151 #14058
14+
* fix(populate): allow deselecting discriminator key when populating #14155 #3230
15+
* fix: allow adding discriminators using Schema.prototype.discriminator() to subdocuments after defining parent schema #14131 #14109
16+
* fix(schema): avoid creating unnecessary clone of schematype in nested array so nested document arrays use correct constructor #14128 #14101
17+
* fix(populate): call transform object with single id instead of array when populating a justOne path under an array #14135 #14073
18+
* types: add back mistakenly removed findByIdAndRemove() function signature #14136 #14132
19+
120
8.0.2 / 2023-11-28
221
==================
322
* fix(populate): set populated docs in correct order when populating virtual underneath doc array with justOne #14105

docs/connections.md

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -267,18 +267,42 @@ connection may emit.
267267

268268
* `connecting`: Emitted when Mongoose starts making its initial connection to the MongoDB server
269269
* `connected`: Emitted when Mongoose successfully makes its initial connection to the MongoDB server, or when Mongoose reconnects after losing connectivity. May be emitted multiple times if Mongoose loses connectivity.
270-
* `open`: Emitted after `'connected'` and `onOpen` is executed on all of this connection's models.
271-
* `disconnecting`: Your app called [`Connection#close()`](api/connection.html#connection_Connection-close) to disconnect from MongoDB
270+
* `open`: Emitted after `'connected'` and `onOpen` is executed on all of this connection's models. May be emitted multiple times if Mongoose loses connectivity.
271+
* `disconnecting`: Your app called [`Connection#close()`](api/connection.html#connection_Connection-close) to disconnect from MongoDB. This includes calling `mongoose.disconnect()`, which calls `close()` on all connections.
272272
* `disconnected`: Emitted when Mongoose lost connection to the MongoDB server. This event may be due to your code explicitly closing the connection, the database server crashing, or network connectivity issues.
273273
* `close`: Emitted after [`Connection#close()`](api/connection.html#connection_Connection-close) successfully closes the connection. If you call `conn.close()`, you'll get both a 'disconnected' event and a 'close' event.
274274
* `reconnected`: Emitted if Mongoose lost connectivity to MongoDB and successfully reconnected. Mongoose attempts to [automatically reconnect](https://thecodebarbarian.com/managing-connections-with-the-mongodb-node-driver.html) when it loses connection to the database.
275275
* `error`: Emitted if an error occurs on a connection, like a `parseError` due to malformed data or a payload larger than [16MB](https://www.mongodb.com/docs/manual/reference/limits/#BSON-Document-Size).
276-
* `fullsetup`: Emitted when you're connecting to a replica set and Mongoose has successfully connected to the primary and at least one secondary.
277-
* `all`: Emitted when you're connecting to a replica set and Mongoose has successfully connected to all servers specified in your connection string.
278276

279-
When you're connecting to a single MongoDB server (a "standalone"), Mongoose will emit 'disconnected' if it gets
280-
disconnected from the standalone server, and 'connected' if it successfully connects to the standalone. In a
281-
replica set, Mongoose will emit 'disconnected' if it loses connectivity to the replica set primary, and 'connected' if it manages to reconnect to the replica set primary.
277+
When you're connecting to a single MongoDB server (a ["standalone"](https://www.mongodb.com/docs/cloud-manager/tutorial/deploy-standalone/)), Mongoose will emit `disconnected` if it gets
278+
disconnected from the standalone server, and `connected` if it successfully connects to the standalone. In a
279+
[replica set](https://www.mongodb.com/docs/manual/replication/), Mongoose will emit `disconnected` if it loses connectivity to the replica set primary, and `connected` if it manages to reconnect to the replica set primary.
280+
281+
If you are using `mongoose.connect()`, you can use the following to listen to the above events:
282+
283+
```javascript
284+
mongoose.connection.on('connected', () => console.log('connected'));
285+
mongoose.connection.on('open', () => console.log('open'));
286+
mongoose.connection.on('disconnected', () => console.log('disconnected'));
287+
mongoose.connection.on('reconnected', () => console.log('reconnected'));
288+
mongoose.connection.on('disconnecting', () => console.log('disconnecting'));
289+
mongoose.connection.on('close', () => console.log('close'));
290+
291+
mongoose.connect('mongodb://127.0.0.1:27017/mongoose_test');
292+
```
293+
294+
With `mongoose.createConnection()`, use the following instead:
295+
296+
```javascript
297+
const conn = mongoose.createConnection('mongodb://127.0.0.1:27017/mongoose_test');
298+
299+
conn.on('connected', () => console.log('connected'));
300+
conn.on('open', () => console.log('open'));
301+
conn.on('disconnected', () => console.log('disconnected'));
302+
conn.on('reconnected', () => console.log('reconnected'));
303+
conn.on('disconnecting', () => console.log('disconnecting'));
304+
conn.on('close', () => console.log('close'));
305+
```
282306

283307
<h2 id="keepAlive"><a href="#keepAlive">A note about keepAlive</a></h2>
284308

docs/version-support.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ We ship all new bug fixes and features to 7.x.
1010

1111
## Mongoose 6
1212

13-
Mongoose 6.x (released August 24, 2021) is currently in legacy support.
14-
We will continue to ship bug fixes to Mongoose 6 until August 24, 2023.
15-
After August 24, 2023, we will only ship security fixes, and backport requested fixes to Mongoose 6.
13+
Mongoose 6.x (released August 24, 2021) is currently only receiving security fixes and requested bug fixes as of August 24, 2023.
1614
Please open a [bug report on GitHub](https://github.com/Automattic/mongoose/issues/new?assignees=&labels=&template=bug.yml) to request backporting a fix to Mongoose 6.
1715

1816
We are **not** actively backporting any new features from Mongoose 7 into Mongoose 6.

lib/document.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3691,8 +3691,7 @@ Document.prototype.$toObject = function(options, json) {
36913691
const schemaOptions = this.$__schema && this.$__schema.options || {};
36923692
// merge base default options with Schema's set default options if available.
36933693
// `clone` is necessary here because `utils.options` directly modifies the second input.
3694-
defaultOptions = utils.options(defaultOptions, clone(baseOptions));
3695-
defaultOptions = utils.options(defaultOptions, clone(schemaOptions[path] || {}));
3694+
defaultOptions = { ...defaultOptions, ...baseOptions, ...schemaOptions[path] };
36963695

36973696
// If options do not exist or is not an object, set it to empty object
36983697
options = utils.isPOJO(options) ? { ...options } : {};
@@ -3754,7 +3753,7 @@ Document.prototype.$toObject = function(options, json) {
37543753
}
37553754

37563755
// merge default options with input options.
3757-
options = utils.options(defaultOptions, options);
3756+
options = { ...defaultOptions, ...options };
37583757
options._isNested = true;
37593758
options.json = json;
37603759
options.minimize = _minimize;

lib/helpers/clone.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function clone(obj, options, isArrayChild) {
5454
ret = obj.toObject(options);
5555
}
5656

57-
if (options && options.minimize && isSingleNested && Object.keys(ret).length === 0) {
57+
if (options && options.minimize && !obj.constructor.$__required && isSingleNested && Object.keys(ret).length === 0) {
5858
return undefined;
5959
}
6060

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
module.exports = applyEmbeddedDiscriminators;
4+
5+
function applyEmbeddedDiscriminators(schema, seen = new WeakSet()) {
6+
if (seen.has(schema)) {
7+
return;
8+
}
9+
seen.add(schema);
10+
for (const path of Object.keys(schema.paths)) {
11+
const schemaType = schema.paths[path];
12+
if (!schemaType.schema) {
13+
continue;
14+
}
15+
applyEmbeddedDiscriminators(schemaType.schema, seen);
16+
if (!schemaType.schema._applyDiscriminators) {
17+
continue;
18+
}
19+
for (const disc of schemaType.schema._applyDiscriminators.keys()) {
20+
schemaType.discriminator(disc, schemaType.schema._applyDiscriminators.get(disc));
21+
}
22+
}
23+
}

lib/helpers/populate/assignVals.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ module.exports = function assignVals(o) {
3939
const options = o.options;
4040
const count = o.count && o.isVirtual;
4141
let i;
42+
let setValueIndex = 0;
4243

4344
function setValue(val) {
45+
++setValueIndex;
4446
if (count) {
4547
return val;
4648
}
@@ -80,11 +82,14 @@ module.exports = function assignVals(o) {
8082
return valueFilter(val[0], options, populateOptions, _allIds);
8183
} else if (o.justOne === false && !Array.isArray(val)) {
8284
return valueFilter([val], options, populateOptions, _allIds);
85+
} else if (o.justOne === true && !Array.isArray(val) && Array.isArray(_allIds)) {
86+
return valueFilter(val, options, populateOptions, val == null ? val : _allIds[setValueIndex - 1]);
8387
}
8488
return valueFilter(val, options, populateOptions, _allIds);
8589
}
8690

8791
for (i = 0; i < docs.length; ++i) {
92+
setValueIndex = 0;
8893
const _path = o.path.endsWith('.$*') ? o.path.slice(0, -3) : o.path;
8994
const existingVal = mpath.get(_path, docs[i], lookupLocalFields);
9095
if (existingVal == null && !getVirtual(o.originalModel.schema, _path)) {

lib/helpers/projection/isExclusive.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@ module.exports = function isExclusive(projection) {
1212
}
1313

1414
const keys = Object.keys(projection);
15-
let ki = keys.length;
1615
let exclude = null;
1716

18-
if (ki === 1 && keys[0] === '_id') {
17+
if (keys.length === 1 && keys[0] === '_id') {
1918
exclude = !projection._id;
2019
} else {
21-
while (ki--) {
20+
for (let ki = 0; ki < keys.length; ++ki) {
2221
// Does this projection explicitly define inclusion/exclusion?
2322
// Explicitly avoid `$meta` and `$slice`
2423
const key = keys[ki];

lib/model.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4300,7 +4300,7 @@ function populate(model, docs, options, callback) {
43004300
select = select.replace(excludeIdRegGlobal, ' ');
43014301
} else {
43024302
// preserve original select conditions by copying
4303-
select = utils.object.shallowCopy(select);
4303+
select = { ...select };
43044304
delete select._id;
43054305
}
43064306
}

lib/mongoose.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const sanitizeFilter = require('./helpers/query/sanitizeFilter');
3030
const isBsonType = require('./helpers/isBsonType');
3131
const MongooseError = require('./error/mongooseError');
3232
const SetOptionError = require('./error/setOptionError');
33+
const applyEmbeddedDiscriminators = require('./helpers/discriminator/applyEmbeddedDiscriminators');
3334

3435
const defaultMongooseSymbol = Symbol.for('mongoose:default');
3536

@@ -627,6 +628,8 @@ Mongoose.prototype._model = function(name, schema, collection, options) {
627628
}
628629
}
629630

631+
applyEmbeddedDiscriminators(schema);
632+
630633
return model;
631634
};
632635

lib/query.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4791,16 +4791,14 @@ Query.prototype._castFields = function _castFields(fields) {
47914791
elemMatchKeys,
47924792
keys,
47934793
key,
4794-
out,
4795-
i;
4794+
out;
47964795

47974796
if (fields) {
47984797
keys = Object.keys(fields);
47994798
elemMatchKeys = [];
4800-
i = keys.length;
48014799

48024800
// collect $elemMatch args
4803-
while (i--) {
4801+
for (let i = 0; i < keys.length; ++i) {
48044802
key = keys[i];
48054803
if (fields[key].$elemMatch) {
48064804
selected || (selected = {});
@@ -4819,8 +4817,7 @@ Query.prototype._castFields = function _castFields(fields) {
48194817
}
48204818

48214819
// apply the casted field args
4822-
i = elemMatchKeys.length;
4823-
while (i--) {
4820+
for (let i = 0; i < elemMatchKeys.length; ++i) {
48244821
key = elemMatchKeys[i];
48254822
fields[key] = out[key];
48264823
}

lib/queryHelpers.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,12 @@ exports.applyPaths = function applyPaths(fields, schema) {
180180
if (!isDefiningProjection(field)) {
181181
continue;
182182
}
183-
// `_id: 1, name: 0` is a mixed inclusive/exclusive projection in
184-
// MongoDB 4.0 and earlier, but not in later versions.
185183
if (keys[keyIndex] === '_id' && keys.length > 1) {
186184
continue;
187185
}
186+
if (keys[keyIndex] === schema.options.discriminatorKey && keys.length > 1 && field != null && !field) {
187+
continue;
188+
}
188189
exclude = !field;
189190
break;
190191
}

lib/schema.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ Schema.prototype.defaultOptions = function(options) {
560560
const strict = 'strict' in baseOptions ? baseOptions.strict : true;
561561
const strictQuery = 'strictQuery' in baseOptions ? baseOptions.strictQuery : false;
562562
const id = 'id' in baseOptions ? baseOptions.id : true;
563-
options = utils.options({
563+
options = {
564564
strict,
565565
strictQuery,
566566
bufferCommands: true,
@@ -577,8 +577,9 @@ Schema.prototype.defaultOptions = function(options) {
577577
// the following are only applied at construction time
578578
_id: true,
579579
id: id,
580-
typeKey: 'type'
581-
}, clone(options));
580+
typeKey: 'type',
581+
...options
582+
};
582583

583584
if (options.versionKey && typeof options.versionKey !== 'string') {
584585
throw new MongooseError('`versionKey` must be falsy or string, got `' + (typeof options.versionKey) + '`');

lib/schema/bigint.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
const CastError = require('../error/cast');
88
const SchemaType = require('../schemaType');
99
const castBigInt = require('../cast/bigint');
10-
const utils = require('../utils');
1110

1211
/**
1312
* BigInt SchemaType constructor.
@@ -177,12 +176,13 @@ SchemaBigInt.prototype.cast = function(value) {
177176
* ignore
178177
*/
179178

180-
SchemaBigInt.$conditionalHandlers = utils.options(SchemaType.prototype.$conditionalHandlers, {
179+
SchemaBigInt.$conditionalHandlers = {
180+
...SchemaType.prototype.$conditionalHandlers,
181181
$gt: handleSingle,
182182
$gte: handleSingle,
183183
$lt: handleSingle,
184184
$lte: handleSingle
185-
});
185+
};
186186

187187
/*!
188188
* ignore

lib/schema/boolean.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
const CastError = require('../error/cast');
88
const SchemaType = require('../schemaType');
99
const castBoolean = require('../cast/boolean');
10-
const utils = require('../utils');
1110

1211
/**
1312
* Boolean SchemaType constructor.
@@ -235,8 +234,7 @@ SchemaBoolean.prototype.cast = function(value) {
235234
}
236235
};
237236

238-
SchemaBoolean.$conditionalHandlers =
239-
utils.options(SchemaType.prototype.$conditionalHandlers, {});
237+
SchemaBoolean.$conditionalHandlers = { ...SchemaType.prototype.$conditionalHandlers };
240238

241239
/**
242240
* Casts contents for queries.

lib/schema/buffer.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -250,17 +250,17 @@ function handleSingle(val, context) {
250250
return this.castForQuery(null, val, context);
251251
}
252252

253-
SchemaBuffer.prototype.$conditionalHandlers =
254-
utils.options(SchemaType.prototype.$conditionalHandlers, {
255-
$bitsAllClear: handleBitwiseOperator,
256-
$bitsAnyClear: handleBitwiseOperator,
257-
$bitsAllSet: handleBitwiseOperator,
258-
$bitsAnySet: handleBitwiseOperator,
259-
$gt: handleSingle,
260-
$gte: handleSingle,
261-
$lt: handleSingle,
262-
$lte: handleSingle
263-
});
253+
SchemaBuffer.prototype.$conditionalHandlers = {
254+
...SchemaType.prototype.$conditionalHandlers,
255+
$bitsAllClear: handleBitwiseOperator,
256+
$bitsAnyClear: handleBitwiseOperator,
257+
$bitsAllSet: handleBitwiseOperator,
258+
$bitsAnySet: handleBitwiseOperator,
259+
$gt: handleSingle,
260+
$gte: handleSingle,
261+
$lt: handleSingle,
262+
$lte: handleSingle
263+
};
264264

265265
/**
266266
* Casts contents for queries.

lib/schema/date.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -388,13 +388,13 @@ function handleSingle(val) {
388388
return this.cast(val);
389389
}
390390

391-
SchemaDate.prototype.$conditionalHandlers =
392-
utils.options(SchemaType.prototype.$conditionalHandlers, {
393-
$gt: handleSingle,
394-
$gte: handleSingle,
395-
$lt: handleSingle,
396-
$lte: handleSingle
397-
});
391+
SchemaDate.prototype.$conditionalHandlers = {
392+
...SchemaType.prototype.$conditionalHandlers,
393+
$gt: handleSingle,
394+
$gte: handleSingle,
395+
$lt: handleSingle,
396+
$lte: handleSingle
397+
};
398398

399399

400400
/**

lib/schema/decimal128.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
const SchemaType = require('../schemaType');
88
const CastError = SchemaType.CastError;
99
const castDecimal128 = require('../cast/decimal128');
10-
const utils = require('../utils');
1110
const isBsonType = require('../helpers/isBsonType');
1211

1312
/**
@@ -214,13 +213,13 @@ function handleSingle(val) {
214213
return this.cast(val);
215214
}
216215

217-
SchemaDecimal128.prototype.$conditionalHandlers =
218-
utils.options(SchemaType.prototype.$conditionalHandlers, {
219-
$gt: handleSingle,
220-
$gte: handleSingle,
221-
$lt: handleSingle,
222-
$lte: handleSingle
223-
});
216+
SchemaDecimal128.prototype.$conditionalHandlers = {
217+
...SchemaType.prototype.$conditionalHandlers,
218+
$gt: handleSingle,
219+
$gte: handleSingle,
220+
$lt: handleSingle,
221+
$lte: handleSingle
222+
};
224223

225224
/*!
226225
* Module exports.

0 commit comments

Comments
 (0)