mongoose 8.8.4 → 8.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.umd.js +1 -1
- package/lib/cast/double.js +50 -0
- package/lib/cast/int32.js +36 -0
- package/lib/connection.js +220 -18
- package/lib/cursor/aggregationCursor.js +1 -2
- package/lib/document.js +19 -7
- package/lib/drivers/node-mongodb-native/collection.js +0 -1
- package/lib/drivers/node-mongodb-native/connection.js +0 -4
- package/lib/helpers/clone.js +5 -0
- package/lib/helpers/model/castBulkWrite.js +218 -205
- package/lib/helpers/model/discriminator.js +1 -0
- package/lib/helpers/populate/getModelsMapForPopulate.js +7 -0
- package/lib/helpers/schema/getIndexes.js +5 -0
- package/lib/model.js +71 -107
- package/lib/mongoose.js +20 -20
- package/lib/query.js +6 -20
- package/lib/queryHelpers.js +13 -32
- package/lib/schema/bigint.js +2 -2
- package/lib/schema/double.js +212 -0
- package/lib/schema/index.js +2 -0
- package/lib/schema/int32.js +249 -0
- package/lib/schema/string.js +10 -10
- package/lib/schema.js +60 -7
- package/lib/schemaType.js +36 -8
- package/lib/validOptions.js +1 -0
- package/package.json +5 -5
- package/types/expressions.d.ts +102 -0
- package/types/index.d.ts +1 -1
- package/types/indexes.d.ts +4 -2
- package/types/inferschematype.d.ts +29 -27
- package/types/populate.d.ts +2 -0
- package/types/schematypes.d.ts +34 -1
- package/types/types.d.ts +5 -3
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const BSON = require('bson');
|
|
5
|
+
const isBsonType = require('../helpers/isBsonType');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Given a value, cast it to a IEEE 754-2008 floating point, or throw an `Error` if the value
|
|
9
|
+
* cannot be casted. `null`, `undefined`, and `NaN` are considered valid inputs.
|
|
10
|
+
*
|
|
11
|
+
* @param {Any} value
|
|
12
|
+
* @return {Number}
|
|
13
|
+
* @throws {Error} if `value` does not represent a IEEE 754-2008 floating point. If casting from a string, see [BSON Double.fromString API documentation](https://mongodb.github.io/node-mongodb-native/Next/classes/BSON.Double.html#fromString)
|
|
14
|
+
* @api private
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
module.exports = function castDouble(val) {
|
|
18
|
+
if (val == null || val === '') {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let coercedVal;
|
|
23
|
+
if (isBsonType(val, 'Long')) {
|
|
24
|
+
coercedVal = val.toNumber();
|
|
25
|
+
} else if (typeof val === 'string') {
|
|
26
|
+
try {
|
|
27
|
+
coercedVal = BSON.Double.fromString(val);
|
|
28
|
+
return coercedVal;
|
|
29
|
+
} catch {
|
|
30
|
+
assert.ok(false);
|
|
31
|
+
}
|
|
32
|
+
} else if (typeof val === 'object') {
|
|
33
|
+
const tempVal = val.valueOf() ?? val.toString();
|
|
34
|
+
// ex: { a: 'im an object, valueOf: () => 'helloworld' } // throw an error
|
|
35
|
+
if (typeof tempVal === 'string') {
|
|
36
|
+
try {
|
|
37
|
+
coercedVal = BSON.Double.fromString(val);
|
|
38
|
+
return coercedVal;
|
|
39
|
+
} catch {
|
|
40
|
+
assert.ok(false);
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
coercedVal = Number(tempVal);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
coercedVal = Number(val);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return new BSON.Double(coercedVal);
|
|
50
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const isBsonType = require('../helpers/isBsonType');
|
|
4
|
+
const assert = require('assert');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Given a value, cast it to a Int32, or throw an `Error` if the value
|
|
8
|
+
* cannot be casted. `null` and `undefined` are considered valid.
|
|
9
|
+
*
|
|
10
|
+
* @param {Any} value
|
|
11
|
+
* @return {Number}
|
|
12
|
+
* @throws {Error} if `value` does not represent an integer, or is outside the bounds of an 32-bit integer.
|
|
13
|
+
* @api private
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
module.exports = function castInt32(val) {
|
|
17
|
+
if (val == null) {
|
|
18
|
+
return val;
|
|
19
|
+
}
|
|
20
|
+
if (val === '') {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const coercedVal = isBsonType(val, 'Long') ? val.toNumber() : Number(val);
|
|
25
|
+
|
|
26
|
+
const INT32_MAX = 0x7FFFFFFF;
|
|
27
|
+
const INT32_MIN = -0x80000000;
|
|
28
|
+
|
|
29
|
+
if (coercedVal === (coercedVal | 0) &&
|
|
30
|
+
coercedVal >= INT32_MIN &&
|
|
31
|
+
coercedVal <= INT32_MAX
|
|
32
|
+
) {
|
|
33
|
+
return coercedVal;
|
|
34
|
+
}
|
|
35
|
+
assert.ok(false);
|
|
36
|
+
};
|
package/lib/connection.js
CHANGED
|
@@ -8,6 +8,7 @@ const ChangeStream = require('./cursor/changeStream');
|
|
|
8
8
|
const EventEmitter = require('events').EventEmitter;
|
|
9
9
|
const Schema = require('./schema');
|
|
10
10
|
const STATES = require('./connectionState');
|
|
11
|
+
const MongooseBulkWriteError = require('./error/bulkWriteError');
|
|
11
12
|
const MongooseError = require('./error/index');
|
|
12
13
|
const ServerSelectionError = require('./error/serverSelection');
|
|
13
14
|
const SyncIndexesError = require('./error/syncIndexes');
|
|
@@ -15,9 +16,13 @@ const applyPlugins = require('./helpers/schema/applyPlugins');
|
|
|
15
16
|
const clone = require('./helpers/clone');
|
|
16
17
|
const driver = require('./driver');
|
|
17
18
|
const get = require('./helpers/get');
|
|
19
|
+
const getDefaultBulkwriteResult = require('./helpers/getDefaultBulkwriteResult');
|
|
18
20
|
const immediate = require('./helpers/immediate');
|
|
19
21
|
const utils = require('./utils');
|
|
20
22
|
const CreateCollectionsError = require('./error/createCollectionsError');
|
|
23
|
+
const castBulkWrite = require('./helpers/model/castBulkWrite');
|
|
24
|
+
const { modelSymbol } = require('./helpers/symbols');
|
|
25
|
+
const isPromise = require('./helpers/isPromise');
|
|
21
26
|
|
|
22
27
|
const arrayAtomicsSymbol = require('./helpers/symbols').arrayAtomicsSymbol;
|
|
23
28
|
const sessionNewDocuments = require('./helpers/symbols').sessionNewDocuments;
|
|
@@ -111,6 +116,9 @@ Object.defineProperty(Connection.prototype, 'readyState', {
|
|
|
111
116
|
if (
|
|
112
117
|
this._readyState === STATES.connected &&
|
|
113
118
|
this._lastHeartbeatAt != null &&
|
|
119
|
+
// LoadBalanced topology (behind haproxy, including Atlas serverless instances) don't use heartbeats,
|
|
120
|
+
// so we can't use this check in that case.
|
|
121
|
+
this.client?.topology?.s?.description?.type !== 'LoadBalanced' &&
|
|
114
122
|
typeof this.client?.topology?.s?.description?.heartbeatFrequencyMS === 'number' &&
|
|
115
123
|
Date.now() - this._lastHeartbeatAt >= this.client.topology.s.description.heartbeatFrequencyMS * 2) {
|
|
116
124
|
return STATES.disconnected;
|
|
@@ -150,7 +158,7 @@ Object.defineProperty(Connection.prototype, 'readyState', {
|
|
|
150
158
|
* @api public
|
|
151
159
|
*/
|
|
152
160
|
|
|
153
|
-
Connection.prototype.get = function(key) {
|
|
161
|
+
Connection.prototype.get = function getOption(key) {
|
|
154
162
|
if (this.config.hasOwnProperty(key)) {
|
|
155
163
|
return this.config[key];
|
|
156
164
|
}
|
|
@@ -178,7 +186,7 @@ Connection.prototype.get = function(key) {
|
|
|
178
186
|
* @api public
|
|
179
187
|
*/
|
|
180
188
|
|
|
181
|
-
Connection.prototype.set = function(key, val) {
|
|
189
|
+
Connection.prototype.set = function setOption(key, val) {
|
|
182
190
|
if (this.config.hasOwnProperty(key)) {
|
|
183
191
|
this.config[key] = val;
|
|
184
192
|
return val;
|
|
@@ -416,6 +424,178 @@ Connection.prototype.createCollection = async function createCollection(collecti
|
|
|
416
424
|
return this.db.createCollection(collection, options);
|
|
417
425
|
};
|
|
418
426
|
|
|
427
|
+
/**
|
|
428
|
+
* _Requires MongoDB Server 8.0 or greater_. Executes bulk write operations across multiple models in a single operation.
|
|
429
|
+
* You must specify the `model` for each operation: Mongoose will use `model` for casting and validation, as well as
|
|
430
|
+
* determining which collection to apply the operation to.
|
|
431
|
+
*
|
|
432
|
+
* #### Example:
|
|
433
|
+
* const Test = mongoose.model('Test', new Schema({ name: String }));
|
|
434
|
+
*
|
|
435
|
+
* await db.bulkWrite([
|
|
436
|
+
* { model: Test, name: 'insertOne', document: { name: 'test1' } }, // Can specify model as a Model class...
|
|
437
|
+
* { model: 'Test', name: 'insertOne', document: { name: 'test2' } } // or as a model name
|
|
438
|
+
* ], { ordered: false });
|
|
439
|
+
*
|
|
440
|
+
* @method bulkWrite
|
|
441
|
+
* @param {Array} ops
|
|
442
|
+
* @param {Object} [options]
|
|
443
|
+
* @param {Boolean} [options.ordered] If false, perform unordered operations. If true, perform ordered operations.
|
|
444
|
+
* @param {Session} [options.session] The session to use for the operation.
|
|
445
|
+
* @return {Promise}
|
|
446
|
+
* @see MongoDB https://www.mongodb.com/docs/manual/reference/command/bulkWrite/#mongodb-dbcommand-dbcmd.bulkWrite
|
|
447
|
+
* @api public
|
|
448
|
+
*/
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
|
|
452
|
+
await this._waitForConnect();
|
|
453
|
+
options = options || {};
|
|
454
|
+
|
|
455
|
+
const ordered = options.ordered == null ? true : options.ordered;
|
|
456
|
+
const asyncLocalStorage = this.base.transactionAsyncLocalStorage?.getStore();
|
|
457
|
+
if ((!options || !options.hasOwnProperty('session')) && asyncLocalStorage?.session != null) {
|
|
458
|
+
options = { ...options, session: asyncLocalStorage.session };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const now = this.base.now();
|
|
462
|
+
|
|
463
|
+
let res = null;
|
|
464
|
+
if (ordered) {
|
|
465
|
+
const opsToSend = [];
|
|
466
|
+
for (const op of ops) {
|
|
467
|
+
if (typeof op.model !== 'string' && !op.model?.[modelSymbol]) {
|
|
468
|
+
throw new MongooseError('Must specify model in Connection.prototype.bulkWrite() operations');
|
|
469
|
+
}
|
|
470
|
+
const Model = op.model[modelSymbol] ? op.model : this.model(op.model);
|
|
471
|
+
|
|
472
|
+
if (op.name == null) {
|
|
473
|
+
throw new MongooseError('Must specify operation name in Connection.prototype.bulkWrite()');
|
|
474
|
+
}
|
|
475
|
+
if (!castBulkWrite.cast.hasOwnProperty(op.name)) {
|
|
476
|
+
throw new MongooseError(`Unrecognized bulkWrite() operation name ${op.name}`);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
await castBulkWrite.cast[op.name](Model, op, options, now);
|
|
480
|
+
opsToSend.push({ ...op, namespace: Model.namespace() });
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
res = await this.client.bulkWrite(opsToSend, options);
|
|
484
|
+
} else {
|
|
485
|
+
const validOps = [];
|
|
486
|
+
const validOpIndexes = [];
|
|
487
|
+
let validationErrors = [];
|
|
488
|
+
const asyncValidations = [];
|
|
489
|
+
const results = [];
|
|
490
|
+
for (let i = 0; i < ops.length; ++i) {
|
|
491
|
+
const op = ops[i];
|
|
492
|
+
if (typeof op.model !== 'string' && !op.model?.[modelSymbol]) {
|
|
493
|
+
const error = new MongooseError('Must specify model in Connection.prototype.bulkWrite() operations');
|
|
494
|
+
validationErrors.push({ index: i, error: error });
|
|
495
|
+
results[i] = error;
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
let Model;
|
|
499
|
+
try {
|
|
500
|
+
Model = op.model[modelSymbol] ? op.model : this.model(op.model);
|
|
501
|
+
} catch (error) {
|
|
502
|
+
validationErrors.push({ index: i, error: error });
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
if (op.name == null) {
|
|
506
|
+
const error = new MongooseError('Must specify operation name in Connection.prototype.bulkWrite()');
|
|
507
|
+
validationErrors.push({ index: i, error: error });
|
|
508
|
+
results[i] = error;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
if (!castBulkWrite.cast.hasOwnProperty(op.name)) {
|
|
512
|
+
const error = new MongooseError(`Unrecognized bulkWrite() operation name ${op.name}`);
|
|
513
|
+
validationErrors.push({ index: i, error: error });
|
|
514
|
+
results[i] = error;
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
let maybePromise = null;
|
|
519
|
+
try {
|
|
520
|
+
maybePromise = castBulkWrite.cast[op.name](Model, op, options, now);
|
|
521
|
+
} catch (error) {
|
|
522
|
+
validationErrors.push({ index: i, error: error });
|
|
523
|
+
results[i] = error;
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
if (isPromise(maybePromise)) {
|
|
527
|
+
asyncValidations.push(
|
|
528
|
+
maybePromise.then(
|
|
529
|
+
() => {
|
|
530
|
+
validOps.push({ ...op, namespace: Model.namespace() });
|
|
531
|
+
validOpIndexes.push(i);
|
|
532
|
+
},
|
|
533
|
+
error => {
|
|
534
|
+
validationErrors.push({ index: i, error: error });
|
|
535
|
+
results[i] = error;
|
|
536
|
+
}
|
|
537
|
+
)
|
|
538
|
+
);
|
|
539
|
+
} else {
|
|
540
|
+
validOps.push({ ...op, namespace: Model.namespace() });
|
|
541
|
+
validOpIndexes.push(i);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (asyncValidations.length > 0) {
|
|
546
|
+
await Promise.all(asyncValidations);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
validationErrors = validationErrors.
|
|
550
|
+
sort((v1, v2) => v1.index - v2.index).
|
|
551
|
+
map(v => v.error);
|
|
552
|
+
|
|
553
|
+
if (validOps.length === 0) {
|
|
554
|
+
if (options.throwOnValidationError && validationErrors.length) {
|
|
555
|
+
throw new MongooseBulkWriteError(
|
|
556
|
+
validationErrors,
|
|
557
|
+
results,
|
|
558
|
+
res,
|
|
559
|
+
'bulkWrite'
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
return getDefaultBulkwriteResult();
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
let error;
|
|
566
|
+
[res, error] = await this.client.bulkWrite(validOps, options).
|
|
567
|
+
then(res => ([res, null])).
|
|
568
|
+
catch(err => ([null, err]));
|
|
569
|
+
|
|
570
|
+
if (error) {
|
|
571
|
+
if (validationErrors.length > 0) {
|
|
572
|
+
error.mongoose = error.mongoose || {};
|
|
573
|
+
error.mongoose.validationErrors = validationErrors;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
for (let i = 0; i < validOpIndexes.length; ++i) {
|
|
578
|
+
results[validOpIndexes[i]] = null;
|
|
579
|
+
}
|
|
580
|
+
if (validationErrors.length > 0) {
|
|
581
|
+
if (options.throwOnValidationError) {
|
|
582
|
+
throw new MongooseBulkWriteError(
|
|
583
|
+
validationErrors,
|
|
584
|
+
results,
|
|
585
|
+
res,
|
|
586
|
+
'bulkWrite'
|
|
587
|
+
);
|
|
588
|
+
} else {
|
|
589
|
+
res.mongoose = res.mongoose || {};
|
|
590
|
+
res.mongoose.validationErrors = validationErrors;
|
|
591
|
+
res.mongoose.results = results;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return res;
|
|
597
|
+
};
|
|
598
|
+
|
|
419
599
|
/**
|
|
420
600
|
* Calls `createCollection()` on a models in a series.
|
|
421
601
|
*
|
|
@@ -745,7 +925,7 @@ Connection.prototype._shouldBufferCommands = function _shouldBufferCommands() {
|
|
|
745
925
|
* @api private
|
|
746
926
|
*/
|
|
747
927
|
|
|
748
|
-
Connection.prototype.error = function(err, callback) {
|
|
928
|
+
Connection.prototype.error = function error(err, callback) {
|
|
749
929
|
if (callback) {
|
|
750
930
|
callback(err);
|
|
751
931
|
return null;
|
|
@@ -759,6 +939,7 @@ Connection.prototype.error = function(err, callback) {
|
|
|
759
939
|
/**
|
|
760
940
|
* Called when the connection is opened
|
|
761
941
|
*
|
|
942
|
+
* @emits "open"
|
|
762
943
|
* @api private
|
|
763
944
|
*/
|
|
764
945
|
|
|
@@ -863,11 +1044,21 @@ Connection.prototype.openUri = async function openUri(uri, options) {
|
|
|
863
1044
|
return this;
|
|
864
1045
|
};
|
|
865
1046
|
|
|
866
|
-
|
|
867
|
-
*
|
|
868
|
-
*
|
|
1047
|
+
/**
|
|
1048
|
+
* Listen to events in the Connection
|
|
1049
|
+
*
|
|
1050
|
+
* @param {String} event The event to listen on
|
|
1051
|
+
* @param {Function} callback
|
|
1052
|
+
* @see Connection#readyState https://mongoosejs.com/docs/api/connection.html#Connection.prototype.readyState
|
|
1053
|
+
*
|
|
1054
|
+
* @method on
|
|
1055
|
+
* @instance
|
|
1056
|
+
* @memberOf Connection
|
|
1057
|
+
* @api public
|
|
869
1058
|
*/
|
|
870
1059
|
|
|
1060
|
+
// Treat `on('error')` handlers as handling the initialConnection promise
|
|
1061
|
+
// to avoid uncaught exceptions when using `on('error')`. See gh-14377.
|
|
871
1062
|
Connection.prototype.on = function on(event, callback) {
|
|
872
1063
|
if (event === 'error' && this.$initialConnection) {
|
|
873
1064
|
this.$initialConnection.catch(() => {});
|
|
@@ -875,11 +1066,21 @@ Connection.prototype.on = function on(event, callback) {
|
|
|
875
1066
|
return EventEmitter.prototype.on.call(this, event, callback);
|
|
876
1067
|
};
|
|
877
1068
|
|
|
878
|
-
|
|
879
|
-
*
|
|
880
|
-
*
|
|
1069
|
+
/**
|
|
1070
|
+
* Listen to a event once in the Connection
|
|
1071
|
+
*
|
|
1072
|
+
* @param {String} event The event to listen on
|
|
1073
|
+
* @param {Function} callback
|
|
1074
|
+
* @see Connection#readyState https://mongoosejs.com/docs/api/connection.html#Connection.prototype.readyState
|
|
1075
|
+
*
|
|
1076
|
+
* @method once
|
|
1077
|
+
* @instance
|
|
1078
|
+
* @memberOf Connection
|
|
1079
|
+
* @api public
|
|
881
1080
|
*/
|
|
882
1081
|
|
|
1082
|
+
// Treat `on('error')` handlers as handling the initialConnection promise
|
|
1083
|
+
// to avoid uncaught exceptions when using `on('error')`. See gh-14377.
|
|
883
1084
|
Connection.prototype.once = function on(event, callback) {
|
|
884
1085
|
if (event === 'error' && this.$initialConnection) {
|
|
885
1086
|
this.$initialConnection.catch(() => {});
|
|
@@ -1040,17 +1241,18 @@ Connection.prototype._close = async function _close(force, destroy) {
|
|
|
1040
1241
|
* @api private
|
|
1041
1242
|
*/
|
|
1042
1243
|
|
|
1043
|
-
Connection.prototype.doClose = function() {
|
|
1244
|
+
Connection.prototype.doClose = function doClose() {
|
|
1044
1245
|
throw new Error('Connection#doClose unimplemented by driver');
|
|
1045
1246
|
};
|
|
1046
1247
|
|
|
1047
1248
|
/**
|
|
1048
1249
|
* Called when the connection closes
|
|
1049
1250
|
*
|
|
1251
|
+
* @emits "close"
|
|
1050
1252
|
* @api private
|
|
1051
1253
|
*/
|
|
1052
1254
|
|
|
1053
|
-
Connection.prototype.onClose = function(force) {
|
|
1255
|
+
Connection.prototype.onClose = function onClose(force) {
|
|
1054
1256
|
this.readyState = STATES.disconnected;
|
|
1055
1257
|
|
|
1056
1258
|
// avoid having the collection subscribe to our event emitter
|
|
@@ -1154,7 +1356,7 @@ Connection.prototype.plugin = function(fn, opts) {
|
|
|
1154
1356
|
* @api public
|
|
1155
1357
|
*/
|
|
1156
1358
|
|
|
1157
|
-
Connection.prototype.model = function(name, schema, collection, options) {
|
|
1359
|
+
Connection.prototype.model = function model(name, schema, collection, options) {
|
|
1158
1360
|
if (!(this instanceof Connection)) {
|
|
1159
1361
|
throw new MongooseError('`connection.model()` should not be run with ' +
|
|
1160
1362
|
'`new`. If you are doing `new db.model(foo)(bar)`, use ' +
|
|
@@ -1274,7 +1476,7 @@ Connection.prototype.model = function(name, schema, collection, options) {
|
|
|
1274
1476
|
* @return {Connection} this
|
|
1275
1477
|
*/
|
|
1276
1478
|
|
|
1277
|
-
Connection.prototype.deleteModel = function(name) {
|
|
1479
|
+
Connection.prototype.deleteModel = function deleteModel(name) {
|
|
1278
1480
|
if (typeof name === 'string') {
|
|
1279
1481
|
const model = this.model(name);
|
|
1280
1482
|
if (model == null) {
|
|
@@ -1330,7 +1532,7 @@ Connection.prototype.deleteModel = function(name) {
|
|
|
1330
1532
|
* @return {ChangeStream} mongoose-specific change stream wrapper, inherits from EventEmitter
|
|
1331
1533
|
*/
|
|
1332
1534
|
|
|
1333
|
-
Connection.prototype.watch = function(pipeline, options) {
|
|
1535
|
+
Connection.prototype.watch = function watch(pipeline, options) {
|
|
1334
1536
|
const changeStreamThunk = cb => {
|
|
1335
1537
|
immediate(() => {
|
|
1336
1538
|
if (this.readyState === STATES.connecting) {
|
|
@@ -1379,7 +1581,7 @@ Connection.prototype.asPromise = async function asPromise() {
|
|
|
1379
1581
|
* @return {String[]}
|
|
1380
1582
|
*/
|
|
1381
1583
|
|
|
1382
|
-
Connection.prototype.modelNames = function() {
|
|
1584
|
+
Connection.prototype.modelNames = function modelNames() {
|
|
1383
1585
|
return Object.keys(this.models);
|
|
1384
1586
|
};
|
|
1385
1587
|
|
|
@@ -1391,7 +1593,7 @@ Connection.prototype.modelNames = function() {
|
|
|
1391
1593
|
* @api private
|
|
1392
1594
|
* @return {Boolean} true if the connection should be authenticated after it is opened, otherwise false.
|
|
1393
1595
|
*/
|
|
1394
|
-
Connection.prototype.shouldAuthenticate = function() {
|
|
1596
|
+
Connection.prototype.shouldAuthenticate = function shouldAuthenticate() {
|
|
1395
1597
|
return this.user != null &&
|
|
1396
1598
|
(this.pass != null || this.authMechanismDoesNotRequirePassword());
|
|
1397
1599
|
};
|
|
@@ -1404,7 +1606,7 @@ Connection.prototype.shouldAuthenticate = function() {
|
|
|
1404
1606
|
* @return {Boolean} true if the authentication mechanism specified in the options object requires
|
|
1405
1607
|
* a password, otherwise false.
|
|
1406
1608
|
*/
|
|
1407
|
-
Connection.prototype.authMechanismDoesNotRequirePassword = function() {
|
|
1609
|
+
Connection.prototype.authMechanismDoesNotRequirePassword = function authMechanismDoesNotRequirePassword() {
|
|
1408
1610
|
if (this.options && this.options.auth) {
|
|
1409
1611
|
return noPasswordAuthMechanisms.indexOf(this.options.auth.authMechanism) >= 0;
|
|
1410
1612
|
}
|
|
@@ -1422,7 +1624,7 @@ Connection.prototype.authMechanismDoesNotRequirePassword = function() {
|
|
|
1422
1624
|
* @return {Boolean} true if the provided options object provides enough data to authenticate with,
|
|
1423
1625
|
* otherwise false.
|
|
1424
1626
|
*/
|
|
1425
|
-
Connection.prototype.optionsProvideAuthenticationData = function(options) {
|
|
1627
|
+
Connection.prototype.optionsProvideAuthenticationData = function optionsProvideAuthenticationData(options) {
|
|
1426
1628
|
return (options) &&
|
|
1427
1629
|
(options.user) &&
|
|
1428
1630
|
((options.pass) || this.authMechanismDoesNotRequirePassword());
|
|
@@ -175,11 +175,10 @@ AggregationCursor.prototype._markError = function(error) {
|
|
|
175
175
|
* Marks this cursor as closed. Will stop streaming and subsequent calls to
|
|
176
176
|
* `next()` will error.
|
|
177
177
|
*
|
|
178
|
-
* @param {Function} callback
|
|
179
178
|
* @return {Promise}
|
|
180
179
|
* @api public
|
|
181
180
|
* @method close
|
|
182
|
-
* @emits close
|
|
181
|
+
* @emits "close"
|
|
183
182
|
* @see AggregationCursor.close https://mongodb.github.io/node-mongodb-native/4.9/classes/AggregationCursor.html#close
|
|
184
183
|
*/
|
|
185
184
|
|
package/lib/document.js
CHANGED
|
@@ -624,16 +624,17 @@ Document.prototype.toBSON = function() {
|
|
|
624
624
|
};
|
|
625
625
|
|
|
626
626
|
/**
|
|
627
|
-
*
|
|
627
|
+
* Hydrates this document with the data in `doc`. Does not run setters or mark any paths modified.
|
|
628
628
|
*
|
|
629
|
-
* Called internally after a document is returned from
|
|
629
|
+
* Called internally after a document is returned from MongoDB. Normally,
|
|
630
630
|
* you do **not** need to call this function on your own.
|
|
631
631
|
*
|
|
632
632
|
* This function triggers `init` [middleware](https://mongoosejs.com/docs/middleware.html).
|
|
633
633
|
* Note that `init` hooks are [synchronous](https://mongoosejs.com/docs/middleware.html#synchronous).
|
|
634
634
|
*
|
|
635
|
-
* @param {Object} doc document returned by mongo
|
|
635
|
+
* @param {Object} doc raw document returned by mongo
|
|
636
636
|
* @param {Object} [opts]
|
|
637
|
+
* @param {Boolean} [opts.hydratedPopulatedDocs=false] If true, hydrate and mark as populated any paths that are populated in the raw document
|
|
637
638
|
* @param {Function} [fn]
|
|
638
639
|
* @api public
|
|
639
640
|
* @memberOf Document
|
|
@@ -805,6 +806,14 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
805
806
|
reason: e
|
|
806
807
|
}));
|
|
807
808
|
}
|
|
809
|
+
} else if (opts.hydratedPopulatedDocs) {
|
|
810
|
+
doc[i] = schemaType.cast(value, self, true);
|
|
811
|
+
|
|
812
|
+
if (doc[i] && doc[i].$__ && doc[i].$__.wasPopulated) {
|
|
813
|
+
self.$populated(path, doc[i].$__.wasPopulated.value, doc[i].$__.wasPopulated.options);
|
|
814
|
+
} else if (Array.isArray(doc[i]) && doc[i].length && doc[i][0]?.$__?.wasPopulated) {
|
|
815
|
+
self.$populated(path, doc[i].map(populatedDoc => populatedDoc?.$__?.wasPopulated?.value).filter(val => val != null), doc[i][0].$__.wasPopulated.options);
|
|
816
|
+
}
|
|
808
817
|
} else {
|
|
809
818
|
doc[i] = value;
|
|
810
819
|
}
|
|
@@ -822,7 +831,7 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
822
831
|
*
|
|
823
832
|
* #### Example:
|
|
824
833
|
*
|
|
825
|
-
* weirdCar.updateOne({$inc: {wheels:1}}, { w: 1 }
|
|
834
|
+
* weirdCar.updateOne({$inc: {wheels:1}}, { w: 1 });
|
|
826
835
|
*
|
|
827
836
|
* #### Valid options:
|
|
828
837
|
*
|
|
@@ -834,7 +843,6 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
834
843
|
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.lean()) and the [Mongoose lean tutorial](https://mongoosejs.com/docs/tutorials/lean.html).
|
|
835
844
|
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
836
845
|
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
|
|
837
|
-
* @param {Function} [callback]
|
|
838
846
|
* @return {Query}
|
|
839
847
|
* @api public
|
|
840
848
|
* @memberOf Document
|
|
@@ -1768,6 +1776,11 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1768
1776
|
*/
|
|
1769
1777
|
|
|
1770
1778
|
Document.prototype.$__getValue = function(path) {
|
|
1779
|
+
if (typeof path !== 'string' && !Array.isArray(path)) {
|
|
1780
|
+
throw new TypeError(
|
|
1781
|
+
`Invalid \`path\`. Must be either string or array. Got "${path}" (type ${typeof path})`
|
|
1782
|
+
);
|
|
1783
|
+
}
|
|
1771
1784
|
return utils.getValue(path, this._doc);
|
|
1772
1785
|
};
|
|
1773
1786
|
|
|
@@ -3430,12 +3443,11 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3430
3443
|
* @param {Number} [options.wtimeout] sets a [timeout for the write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](https://mongoosejs.com/docs/guide.html#writeConcern).
|
|
3431
3444
|
* @param {Boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://www.mongodb.com/docs/manual/reference/limits/#Restrictions-on-Field-Names)
|
|
3432
3445
|
* @param {Boolean} [options.timestamps=true] if `false` and [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this `save()`.
|
|
3433
|
-
* @param {Function} [fn] optional callback
|
|
3434
3446
|
* @method save
|
|
3435
3447
|
* @memberOf Document
|
|
3436
3448
|
* @instance
|
|
3437
3449
|
* @throws {DocumentNotFoundError} if this [save updates an existing document](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew()) but the document doesn't exist in the database. For example, you will get this error if the document is [deleted between when you retrieved the document and when you saved it](documents.html#updating).
|
|
3438
|
-
* @return {Promise
|
|
3450
|
+
* @return {Promise}
|
|
3439
3451
|
* @api public
|
|
3440
3452
|
* @see middleware https://mongoosejs.com/docs/middleware.html
|
|
3441
3453
|
*/
|
|
@@ -426,9 +426,6 @@ function _setClient(conn, client, options, dbName) {
|
|
|
426
426
|
}
|
|
427
427
|
|
|
428
428
|
conn.onOpen();
|
|
429
|
-
if (client.topology?.s?.state === 'connected') {
|
|
430
|
-
conn._lastHeartbeatAt = Date.now();
|
|
431
|
-
}
|
|
432
429
|
|
|
433
430
|
for (const i in conn.collections) {
|
|
434
431
|
if (utils.object.hasOwnProperty(conn.collections, i)) {
|
|
@@ -437,7 +434,6 @@ function _setClient(conn, client, options, dbName) {
|
|
|
437
434
|
}
|
|
438
435
|
}
|
|
439
436
|
|
|
440
|
-
|
|
441
437
|
/*!
|
|
442
438
|
* Module exports.
|
|
443
439
|
*/
|
package/lib/helpers/clone.js
CHANGED
|
@@ -11,6 +11,7 @@ const isObject = require('./isObject');
|
|
|
11
11
|
const isPOJO = require('./isPOJO');
|
|
12
12
|
const symbols = require('./symbols');
|
|
13
13
|
const trustedSymbol = require('./query/trusted').trustedSymbol;
|
|
14
|
+
const BSON = require('bson');
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Object clone with Mongoose natives support.
|
|
@@ -30,6 +31,10 @@ function clone(obj, options, isArrayChild) {
|
|
|
30
31
|
if (obj == null) {
|
|
31
32
|
return obj;
|
|
32
33
|
}
|
|
34
|
+
|
|
35
|
+
if (isBsonType(obj, 'Double')) {
|
|
36
|
+
return new BSON.Double(obj.value);
|
|
37
|
+
}
|
|
33
38
|
if (typeof obj === 'number' || typeof obj === 'string' || typeof obj === 'boolean' || typeof obj === 'bigint') {
|
|
34
39
|
return obj;
|
|
35
40
|
}
|