mongoose 6.3.2 → 6.3.5
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/README.md +1 -1
- package/dist/browser.umd.js +1 -1
- package/lib/cast/objectid.js +3 -2
- package/lib/connection.js +1 -1
- package/lib/document.js +53 -47
- package/lib/error/index.js +2 -2
- package/lib/helpers/clone.js +9 -2
- package/lib/helpers/common.js +3 -4
- package/lib/helpers/discriminator/areDiscriminatorValuesEqual.js +2 -2
- package/lib/helpers/isBsonType.js +5 -3
- package/lib/helpers/model/castBulkWrite.js +12 -0
- package/lib/helpers/path/setDottedPath.js +14 -1
- package/lib/helpers/query/cast$expr.js +4 -1
- package/lib/helpers/topology/isAtlas.js +15 -2
- package/lib/index.js +2 -2
- package/lib/model.js +42 -57
- package/lib/query.js +5 -2
- package/lib/queryhelpers.js +3 -2
- package/lib/schema/decimal128.js +4 -4
- package/lib/schema/string.js +2 -1
- package/lib/schema.js +9 -0
- package/lib/types/DocumentArray/methods/index.js +3 -3
- package/lib/types/array/methods/index.js +3 -3
- package/lib/types/map.js +4 -4
- package/lib/utils.js +7 -4
- package/package.json +24 -4
- package/types/aggregate.d.ts +3 -4
- package/types/callback.d.ts +8 -0
- package/types/collection.d.ts +46 -0
- package/types/connection.d.ts +92 -72
- package/types/document.d.ts +5 -5
- package/types/error.d.ts +5 -1
- package/types/helpers.d.ts +33 -0
- package/types/index.d.ts +20 -1856
- package/types/indizes.d.ts +98 -0
- package/types/middlewares.d.ts +14 -0
- package/types/models.d.ts +419 -0
- package/types/populate.d.ts +40 -0
- package/types/query.d.ts +637 -0
- package/types/schematypes.d.ts +418 -0
- package/types/session.d.ts +36 -0
- package/types/types.d.ts +102 -0
- package/types/utility.d.ts +13 -0
- package/types/validation.d.ts +32 -0
package/lib/cast/objectid.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const isBsonType = require('../helpers/isBsonType');
|
|
3
4
|
const ObjectId = require('../driver').get().ObjectId;
|
|
4
5
|
|
|
5
6
|
module.exports = function castObjectId(value) {
|
|
@@ -7,12 +8,12 @@ module.exports = function castObjectId(value) {
|
|
|
7
8
|
return value;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
if (value
|
|
11
|
+
if (isBsonType(value, 'ObjectID')) {
|
|
11
12
|
return value;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
if (value._id) {
|
|
15
|
-
if (value._id
|
|
16
|
+
if (isBsonType(value._id, 'ObjectID')) {
|
|
16
17
|
return value._id;
|
|
17
18
|
}
|
|
18
19
|
if (value._id.toString instanceof Function) {
|
package/lib/connection.js
CHANGED
|
@@ -548,7 +548,7 @@ Connection.prototype.dropDatabase = _wrapConnHelper(function dropDatabase(cb) {
|
|
|
548
548
|
// If `dropDatabase()` is called, this model's collection will not be
|
|
549
549
|
// init-ed. It is sufficiently common to call `dropDatabase()` after
|
|
550
550
|
// `mongoose.connect()` but before creating models that we want to
|
|
551
|
-
// support this. See gh-
|
|
551
|
+
// support this. See gh-6796
|
|
552
552
|
for (const name of Object.keys(this.models)) {
|
|
553
553
|
delete this.models[name].$init;
|
|
554
554
|
}
|
package/lib/document.js
CHANGED
|
@@ -53,6 +53,7 @@ const populateModelSymbol = require('./helpers/symbols').populateModelSymbol;
|
|
|
53
53
|
const scopeSymbol = require('./helpers/symbols').scopeSymbol;
|
|
54
54
|
const schemaMixedSymbol = require('./schema/symbols').schemaMixedSymbol;
|
|
55
55
|
const parentPaths = require('./helpers/path/parentPaths');
|
|
56
|
+
|
|
56
57
|
let DocumentArray;
|
|
57
58
|
let MongooseArray;
|
|
58
59
|
let Embedded;
|
|
@@ -1322,6 +1323,10 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1322
1323
|
|
|
1323
1324
|
if (!schema) {
|
|
1324
1325
|
this.$__set(pathToMark, path, options, constructing, parts, schema, val, priorVal);
|
|
1326
|
+
|
|
1327
|
+
if (pathType === 'nested' && val == null) {
|
|
1328
|
+
cleanModifiedSubpaths(this, path);
|
|
1329
|
+
}
|
|
1325
1330
|
return this;
|
|
1326
1331
|
}
|
|
1327
1332
|
|
|
@@ -1373,7 +1378,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1373
1378
|
})();
|
|
1374
1379
|
|
|
1375
1380
|
let didPopulate = false;
|
|
1376
|
-
if (refMatches && val instanceof Document) {
|
|
1381
|
+
if (refMatches && val instanceof Document && (!val.$__.wasPopulated || utils.deepEqual(val.$__.wasPopulated.value, val._id))) {
|
|
1377
1382
|
const unpopulatedValue = (schema && schema.$isSingleNested) ? schema.cast(val, this) : val._id;
|
|
1378
1383
|
this.$populated(path, unpopulatedValue, { [populateModelSymbol]: val.constructor });
|
|
1379
1384
|
val.$__.wasPopulated = { value: unpopulatedValue };
|
|
@@ -1828,7 +1833,6 @@ Document.prototype.$__path = function(path) {
|
|
|
1828
1833
|
*/
|
|
1829
1834
|
|
|
1830
1835
|
Document.prototype.markModified = function(path, scope) {
|
|
1831
|
-
// console.log('MarkModified', path, new Error().stack);
|
|
1832
1836
|
this.$__.activePaths.modify(path);
|
|
1833
1837
|
if (scope != null && !this.$isSubdocument) {
|
|
1834
1838
|
this.$__.pathsToScopes = this.$__pathsToScopes || {};
|
|
@@ -2520,9 +2524,11 @@ function _getPathsToValidate(doc) {
|
|
|
2520
2524
|
// the children as well
|
|
2521
2525
|
for (const path of paths) {
|
|
2522
2526
|
const _pathType = doc.$__schema.path(path);
|
|
2527
|
+
if (!_pathType) {
|
|
2528
|
+
continue;
|
|
2529
|
+
}
|
|
2523
2530
|
|
|
2524
|
-
if (!_pathType ||
|
|
2525
|
-
!_pathType.$isMongooseArray ||
|
|
2531
|
+
if (!_pathType.$isMongooseArray ||
|
|
2526
2532
|
// To avoid potential performance issues, skip doc arrays whose children
|
|
2527
2533
|
// are not required. `getPositionalPathType()` may be slow, so avoid
|
|
2528
2534
|
// it unless we have a case of #6364
|
|
@@ -2534,8 +2540,7 @@ function _getPathsToValidate(doc) {
|
|
|
2534
2540
|
|
|
2535
2541
|
// gh-11380: optimization. If the array isn't a document array and there's no validators
|
|
2536
2542
|
// on the array type, there's no need to run validation on the individual array elements.
|
|
2537
|
-
if (_pathType &&
|
|
2538
|
-
_pathType.$isMongooseArray &&
|
|
2543
|
+
if (_pathType.$isMongooseArray &&
|
|
2539
2544
|
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
|
2540
2545
|
!_pathType.$embeddedSchemaType.$isMongooseArray && // and arrays of arrays
|
|
2541
2546
|
_pathType.$embeddedSchemaType.validators.length === 0) {
|
|
@@ -3127,48 +3132,48 @@ Document.prototype.$isValid = function(path) {
|
|
|
3127
3132
|
|
|
3128
3133
|
Document.prototype.$__reset = function reset() {
|
|
3129
3134
|
let _this = this;
|
|
3130
|
-
DocumentArray || (DocumentArray = require('./types/DocumentArray'));
|
|
3131
3135
|
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3136
|
+
// Skip for subdocuments
|
|
3137
|
+
const subdocs = this.$parent() === this ? this.$getAllSubdocs() : [];
|
|
3138
|
+
const resetArrays = new Set();
|
|
3139
|
+
for (const subdoc of subdocs) {
|
|
3140
|
+
const fullPathWithIndexes = subdoc.$__fullPathWithIndexes();
|
|
3141
|
+
if (this.isModified(fullPathWithIndexes) || isParentInit(fullPathWithIndexes)) {
|
|
3142
|
+
subdoc.$__reset();
|
|
3143
|
+
if (subdoc.$isDocumentArrayElement) {
|
|
3144
|
+
if (!resetArrays.has(subdoc.parentArray())) {
|
|
3145
|
+
const array = subdoc.parentArray();
|
|
3146
|
+
// Mark path to array as init for gh-6818
|
|
3147
|
+
this.$__.activePaths.init(fullPathWithIndexes.replace(/\.\d+$/, '').slice(-subdoc.$basePath - 1));
|
|
3148
|
+
array[arrayAtomicsBackupSymbol] = array[arrayAtomicsSymbol];
|
|
3149
|
+
array[arrayAtomicsSymbol] = {};
|
|
3150
|
+
|
|
3151
|
+
resetArrays.add(array);
|
|
3152
|
+
}
|
|
3153
|
+
} else {
|
|
3154
|
+
if (subdoc.$parent() === this) {
|
|
3155
|
+
this.$__.activePaths.init(subdoc.$basePath);
|
|
3156
|
+
} else if (subdoc.$parent() != null && subdoc.$parent().$isSubdocument) {
|
|
3157
|
+
// If map path underneath subdocument, may end up with a case where
|
|
3158
|
+
// map path is modified but parent still needs to be reset. See gh-10295
|
|
3159
|
+
subdoc.$parent().$__reset();
|
|
3145
3160
|
}
|
|
3146
|
-
doc.$__reset();
|
|
3147
3161
|
}
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3148
3164
|
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
map('init', 'modify', function(i) {
|
|
3157
|
-
return _this.$__getValue(i);
|
|
3158
|
-
}).
|
|
3159
|
-
filter(function(val) {
|
|
3160
|
-
return val && !Array.isArray(val) && val.$isSingleNested;
|
|
3161
|
-
}).
|
|
3162
|
-
forEach(function(doc) {
|
|
3163
|
-
doc.$__reset();
|
|
3164
|
-
if (doc.$parent() === _this) {
|
|
3165
|
-
_this.$__.activePaths.init(doc.$basePath);
|
|
3166
|
-
} else if (doc.$parent() != null && doc.$parent().$isSubdocument) {
|
|
3167
|
-
// If map path underneath subdocument, may end up with a case where
|
|
3168
|
-
// map path is modified but parent still needs to be reset. See gh-10295
|
|
3169
|
-
doc.$parent().$__reset();
|
|
3165
|
+
function isParentInit(path) {
|
|
3166
|
+
path = path.indexOf('.') === -1 ? [path] : path.split('.');
|
|
3167
|
+
let cur = '';
|
|
3168
|
+
for (let i = 0; i < path.length; ++i) {
|
|
3169
|
+
cur += (cur.length ? '.' : '') + path[i];
|
|
3170
|
+
if (_this.$__.activePaths[cur] === 'init') {
|
|
3171
|
+
return true;
|
|
3170
3172
|
}
|
|
3171
|
-
}
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
return false;
|
|
3176
|
+
}
|
|
3172
3177
|
|
|
3173
3178
|
// clear atomics
|
|
3174
3179
|
this.$__dirty().forEach(function(dirt) {
|
|
@@ -3459,9 +3464,9 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3459
3464
|
|
|
3460
3465
|
const path = json ? 'toJSON' : 'toObject';
|
|
3461
3466
|
const baseOptions = this.constructor &&
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3467
|
+
this.constructor.base &&
|
|
3468
|
+
this.constructor.base.options &&
|
|
3469
|
+
get(this.constructor.base.options, path) || {};
|
|
3465
3470
|
const schemaOptions = this.$__schema && this.$__schema.options || {};
|
|
3466
3471
|
// merge base default options with Schema's set default options if available.
|
|
3467
3472
|
// `clone` is necessary here because `utils.options` directly modifies the second input.
|
|
@@ -3498,7 +3503,8 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3498
3503
|
_isNested: true,
|
|
3499
3504
|
json: json,
|
|
3500
3505
|
minimize: _minimize,
|
|
3501
|
-
flattenMaps: flattenMaps
|
|
3506
|
+
flattenMaps: flattenMaps,
|
|
3507
|
+
_seen: (options && options._seen) || new Map()
|
|
3502
3508
|
});
|
|
3503
3509
|
|
|
3504
3510
|
if (utils.hasUserDefinedProperty(options, 'getters')) {
|
package/lib/error/index.js
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* Mongoose-specific errors.
|
|
6
6
|
*
|
|
7
7
|
* #### Example:
|
|
8
|
-
* const Model = mongoose.model('Test', new Schema({ answer: Number }));
|
|
8
|
+
* const Model = mongoose.model('Test', new mongoose.Schema({ answer: Number }));
|
|
9
9
|
* const doc = new Model({ answer: 'not a number' });
|
|
10
10
|
* const err = doc.validateSync();
|
|
11
11
|
*
|
|
12
|
-
* err instanceof mongoose.Error; // true
|
|
12
|
+
* err instanceof mongoose.Error.ValidationError; // true
|
|
13
13
|
*
|
|
14
14
|
* @constructor Error
|
|
15
15
|
* @param {String} msg Error message
|
package/lib/helpers/clone.js
CHANGED
|
@@ -77,7 +77,7 @@ function clone(obj, options, isArrayChild) {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
if (obj
|
|
80
|
+
if (isBsonType(obj, 'ObjectID')) {
|
|
81
81
|
return new ObjectId(obj.id);
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -118,9 +118,16 @@ module.exports = clone;
|
|
|
118
118
|
|
|
119
119
|
function cloneObject(obj, options, isArrayChild) {
|
|
120
120
|
const minimize = options && options.minimize;
|
|
121
|
+
const omitUndefined = options && options.omitUndefined;
|
|
122
|
+
const seen = options && options._seen;
|
|
121
123
|
const ret = {};
|
|
122
124
|
let hasKeys;
|
|
123
125
|
|
|
126
|
+
if (seen && seen.has(obj)) {
|
|
127
|
+
return seen.get(obj);
|
|
128
|
+
} else if (seen) {
|
|
129
|
+
seen.set(obj, ret);
|
|
130
|
+
}
|
|
124
131
|
if (trustedSymbol in obj) {
|
|
125
132
|
ret[trustedSymbol] = obj[trustedSymbol];
|
|
126
133
|
}
|
|
@@ -138,7 +145,7 @@ function cloneObject(obj, options, isArrayChild) {
|
|
|
138
145
|
// Don't pass `isArrayChild` down
|
|
139
146
|
const val = clone(obj[key], options, false);
|
|
140
147
|
|
|
141
|
-
if (minimize === false && typeof val === 'undefined') {
|
|
148
|
+
if ((minimize === false || omitUndefined) && typeof val === 'undefined') {
|
|
142
149
|
delete ret[key];
|
|
143
150
|
} else if (minimize !== true || (typeof val !== 'undefined')) {
|
|
144
151
|
hasKeys || (hasKeys = true);
|
package/lib/helpers/common.js
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const Binary = require('../driver').get().Binary;
|
|
8
|
-
const
|
|
9
|
-
const ObjectId = require('../types/objectid');
|
|
8
|
+
const isBsonType = require('./isBsonType');
|
|
10
9
|
const isMongooseObject = require('./isMongooseObject');
|
|
11
10
|
|
|
12
11
|
exports.flatten = flatten;
|
|
@@ -99,9 +98,9 @@ function shouldFlatten(val) {
|
|
|
99
98
|
return val &&
|
|
100
99
|
typeof val === 'object' &&
|
|
101
100
|
!(val instanceof Date) &&
|
|
102
|
-
!(val
|
|
101
|
+
!isBsonType(val, 'ObjectID') &&
|
|
103
102
|
(!Array.isArray(val) || val.length !== 0) &&
|
|
104
103
|
!(val instanceof Buffer) &&
|
|
105
|
-
!(val
|
|
104
|
+
!isBsonType(val, 'Decimal128') &&
|
|
106
105
|
!(val instanceof Binary);
|
|
107
106
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const isBsonType = require('../isBsonType');
|
|
4
4
|
|
|
5
5
|
module.exports = function areDiscriminatorValuesEqual(a, b) {
|
|
6
6
|
if (typeof a === 'string' && typeof b === 'string') {
|
|
@@ -9,7 +9,7 @@ module.exports = function areDiscriminatorValuesEqual(a, b) {
|
|
|
9
9
|
if (typeof a === 'number' && typeof b === 'number') {
|
|
10
10
|
return a === b;
|
|
11
11
|
}
|
|
12
|
-
if (a
|
|
12
|
+
if (isBsonType(a, 'ObjectID') && isBsonType(b, 'ObjectID')) {
|
|
13
13
|
return a.toString() === b.toString();
|
|
14
14
|
}
|
|
15
15
|
return false;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const get = require('./get');
|
|
4
|
-
|
|
5
3
|
/*!
|
|
6
4
|
* Get the bson type, if it exists
|
|
7
5
|
*/
|
|
8
6
|
|
|
9
7
|
function isBsonType(obj, typename) {
|
|
10
|
-
return
|
|
8
|
+
return (
|
|
9
|
+
typeof obj === 'object' &&
|
|
10
|
+
obj !== null &&
|
|
11
|
+
obj._bsontype === typename
|
|
12
|
+
);
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
module.exports = isBsonType;
|
|
@@ -27,6 +27,12 @@ module.exports = function castBulkWrite(originalModel, op, options) {
|
|
|
27
27
|
doc.$session(options.session);
|
|
28
28
|
}
|
|
29
29
|
op['insertOne']['document'] = doc;
|
|
30
|
+
|
|
31
|
+
if (options.skipValidation || op['insertOne'].skipValidation) {
|
|
32
|
+
callback(null);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
30
36
|
op['insertOne']['document'].$validate({ __noPromise: true }, function(error) {
|
|
31
37
|
if (error) {
|
|
32
38
|
return callback(error, null);
|
|
@@ -154,6 +160,12 @@ module.exports = function castBulkWrite(originalModel, op, options) {
|
|
|
154
160
|
}
|
|
155
161
|
op['replaceOne']['replacement'] = doc;
|
|
156
162
|
|
|
163
|
+
if (options.skipValidation || op['replaceOne'].skipValidation) {
|
|
164
|
+
op['replaceOne']['replacement'] = op['replaceOne']['replacement'].toBSON();
|
|
165
|
+
callback(null);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
157
169
|
op['replaceOne']['replacement'].$validate({ __noPromise: true }, function(error) {
|
|
158
170
|
if (error) {
|
|
159
171
|
return callback(error, null);
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const specialProperties = require('../specialProperties');
|
|
4
|
+
|
|
5
|
+
|
|
3
6
|
module.exports = function setDottedPath(obj, path, val) {
|
|
4
7
|
if (path.indexOf('.') === -1) {
|
|
8
|
+
if (specialProperties.has(path)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
obj[path] = val;
|
|
6
13
|
return;
|
|
7
14
|
}
|
|
8
15
|
const parts = path.split('.');
|
|
16
|
+
|
|
9
17
|
const last = parts.pop();
|
|
10
18
|
let cur = obj;
|
|
11
19
|
for (const part of parts) {
|
|
20
|
+
if (specialProperties.has(part)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
12
23
|
if (cur[part] == null) {
|
|
13
24
|
cur[part] = {};
|
|
14
25
|
}
|
|
@@ -16,5 +27,7 @@ module.exports = function setDottedPath(obj, path, val) {
|
|
|
16
27
|
cur = cur[part];
|
|
17
28
|
}
|
|
18
29
|
|
|
19
|
-
|
|
30
|
+
if (!specialProperties.has(last)) {
|
|
31
|
+
cur[last] = val;
|
|
32
|
+
}
|
|
20
33
|
};
|
|
@@ -4,7 +4,7 @@ const CastError = require('../../error/cast');
|
|
|
4
4
|
const StrictModeError = require('../../error/strict');
|
|
5
5
|
const castNumber = require('../../cast/number');
|
|
6
6
|
|
|
7
|
-
const booleanComparison = new Set(['$and', '$or'
|
|
7
|
+
const booleanComparison = new Set(['$and', '$or']);
|
|
8
8
|
const comparisonOperator = new Set(['$cmp', '$eq', '$lt', '$lte', '$gt', '$gte']);
|
|
9
9
|
const arithmeticOperatorArray = new Set([
|
|
10
10
|
// avoid casting '$add' or '$subtract', because expressions can be either number or date,
|
|
@@ -66,6 +66,7 @@ const dateOperators = new Set([
|
|
|
66
66
|
'$isoWeek',
|
|
67
67
|
'$millisecond'
|
|
68
68
|
]);
|
|
69
|
+
const expressionOperator = new Set(['$not']);
|
|
69
70
|
|
|
70
71
|
module.exports = function cast$expr(val, schema, strictQuery) {
|
|
71
72
|
if (typeof val !== 'object' || val === null) {
|
|
@@ -106,6 +107,8 @@ function _castExpression(val, schema, strictQuery) {
|
|
|
106
107
|
val[key] = castArithmetic(val[key], schema, strictQuery);
|
|
107
108
|
} else if (arithmeticOperatorNumber.has(key)) {
|
|
108
109
|
val[key] = castNumberOperator(val[key], schema, strictQuery);
|
|
110
|
+
} else if (expressionOperator.has(key)) {
|
|
111
|
+
val[key] = _castExpression(val[key], schema, strictQuery);
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
|
|
@@ -8,6 +8,19 @@ module.exports = function isAtlas(topologyDescription) {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const hostnames = Array.from(topologyDescription.servers.keys());
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
if (hostnames.length === 0) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
for (let i = 0, il = hostnames.length; i < il; ++i) {
|
|
17
|
+
const url = new URL(hostnames[i]);
|
|
18
|
+
if (
|
|
19
|
+
url.hostname.endsWith('.mongodb.net') === false ||
|
|
20
|
+
url.port !== '27017'
|
|
21
|
+
) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
13
26
|
};
|
package/lib/index.js
CHANGED
|
@@ -34,6 +34,7 @@ const PromiseProvider = require('./promise_provider');
|
|
|
34
34
|
const shardingPlugin = require('./plugins/sharding');
|
|
35
35
|
const trusted = require('./helpers/query/trusted').trusted;
|
|
36
36
|
const sanitizeFilter = require('./helpers/query/sanitizeFilter');
|
|
37
|
+
const isBsonType = require('./helpers/isBsonType');
|
|
37
38
|
|
|
38
39
|
const defaultMongooseSymbol = Symbol.for('mongoose:default');
|
|
39
40
|
|
|
@@ -995,8 +996,7 @@ Mongoose.prototype.isValidObjectId = function(v) {
|
|
|
995
996
|
*/
|
|
996
997
|
|
|
997
998
|
Mongoose.prototype.isObjectIdOrHexString = function(v) {
|
|
998
|
-
|
|
999
|
-
return v instanceof _mongoose.Types.ObjectId || (typeof v === 'string' && objectIdHexRegexp.test(v));
|
|
999
|
+
return isBsonType(v, 'ObjectID') || (typeof v === 'string' && objectIdHexRegexp.test(v));
|
|
1000
1000
|
};
|
|
1001
1001
|
|
|
1002
1002
|
/**
|
package/lib/model.js
CHANGED
|
@@ -768,6 +768,7 @@ Model.prototype.$__delta = function() {
|
|
|
768
768
|
transform: false,
|
|
769
769
|
virtuals: false,
|
|
770
770
|
getters: false,
|
|
771
|
+
omitUndefined: true,
|
|
771
772
|
_isNested: true
|
|
772
773
|
});
|
|
773
774
|
operand(this, where, delta, data, value);
|
|
@@ -1488,61 +1489,68 @@ Model.syncIndexes = function syncIndexes(options, callback) {
|
|
|
1488
1489
|
* the result of this function would be the result of
|
|
1489
1490
|
* Model.syncIndexes().
|
|
1490
1491
|
*
|
|
1491
|
-
* @param {Object} options
|
|
1492
|
+
* @param {Object} [options]
|
|
1492
1493
|
* @param {Function} callback optional callback
|
|
1493
|
-
* @returns {Promise} which
|
|
1494
|
-
* are indexes that would be dropped in
|
|
1494
|
+
* @returns {Promise} which contains an object, {toDrop, toCreate}, which
|
|
1495
|
+
* are indexes that would be dropped in MongoDB and indexes that would be created in MongoDB.
|
|
1495
1496
|
*/
|
|
1496
1497
|
|
|
1497
1498
|
Model.diffIndexes = function diffIndexes(options, callback) {
|
|
1499
|
+
if (typeof options === 'function') {
|
|
1500
|
+
callback = options;
|
|
1501
|
+
options = null;
|
|
1502
|
+
}
|
|
1498
1503
|
const toDrop = [];
|
|
1499
1504
|
const toCreate = [];
|
|
1500
1505
|
callback = this.$handleCallbackError(callback);
|
|
1501
1506
|
return this.db.base._promiseOrCallback(callback, cb => {
|
|
1502
1507
|
cb = this.$wrapCallback(cb);
|
|
1503
|
-
this.listIndexes((err,
|
|
1504
|
-
if (
|
|
1505
|
-
|
|
1508
|
+
this.listIndexes((err, dbIndexes) => {
|
|
1509
|
+
if (dbIndexes === undefined) {
|
|
1510
|
+
dbIndexes = [];
|
|
1506
1511
|
}
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
for (const
|
|
1512
|
+
dbIndexes = getRelatedDBIndexes(this, dbIndexes);
|
|
1513
|
+
const schemaIndexes = getRelatedSchemaIndexes(this, this.schema.indexes());
|
|
1514
|
+
|
|
1515
|
+
for (const dbIndex of dbIndexes) {
|
|
1511
1516
|
let found = false;
|
|
1512
1517
|
// Never try to drop `_id` index, MongoDB server doesn't allow it
|
|
1513
|
-
if (isDefaultIdIndex(
|
|
1518
|
+
if (isDefaultIdIndex(dbIndex)) {
|
|
1514
1519
|
continue;
|
|
1515
1520
|
}
|
|
1516
1521
|
|
|
1517
|
-
for (const
|
|
1518
|
-
const
|
|
1519
|
-
|
|
1520
|
-
|
|
1522
|
+
for (const [schemaIndexKeysObject, schemaIndexOptions] of schemaIndexes) {
|
|
1523
|
+
const options = decorateDiscriminatorIndexOptions(this.schema, utils.clone(schemaIndexOptions));
|
|
1524
|
+
applySchemaCollation(schemaIndexKeysObject, options, this.schema.options);
|
|
1525
|
+
|
|
1526
|
+
if (isIndexEqual(schemaIndexKeysObject, options, dbIndex)) {
|
|
1521
1527
|
found = true;
|
|
1522
1528
|
}
|
|
1523
1529
|
}
|
|
1524
1530
|
|
|
1525
1531
|
if (!found) {
|
|
1526
|
-
toDrop.push(
|
|
1532
|
+
toDrop.push(dbIndex.name);
|
|
1527
1533
|
}
|
|
1528
1534
|
}
|
|
1529
1535
|
// Iterate through the indexes created on the schema and
|
|
1530
1536
|
// compare against the indexes in mongodb.
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1537
|
+
if (!options || options.toCreate !== false) {
|
|
1538
|
+
for (const schemaIndex of schemaIndexes) {
|
|
1539
|
+
let found = false;
|
|
1540
|
+
const key = schemaIndex[0];
|
|
1541
|
+
const options = decorateDiscriminatorIndexOptions(this.schema, utils.clone(schemaIndex[1]));
|
|
1542
|
+
for (const index of dbIndexes) {
|
|
1543
|
+
if (isDefaultIdIndex(index)) {
|
|
1544
|
+
continue;
|
|
1545
|
+
}
|
|
1546
|
+
if (isIndexEqual(key, options, index)) {
|
|
1547
|
+
found = true;
|
|
1548
|
+
}
|
|
1538
1549
|
}
|
|
1539
|
-
if (
|
|
1540
|
-
|
|
1550
|
+
if (!found) {
|
|
1551
|
+
toCreate.push(key);
|
|
1541
1552
|
}
|
|
1542
1553
|
}
|
|
1543
|
-
if (!found) {
|
|
1544
|
-
toCreate.push(key);
|
|
1545
|
-
}
|
|
1546
1554
|
}
|
|
1547
1555
|
cb(null, { toDrop, toCreate });
|
|
1548
1556
|
});
|
|
@@ -1568,36 +1576,12 @@ Model.cleanIndexes = function cleanIndexes(callback) {
|
|
|
1568
1576
|
return this.db.base._promiseOrCallback(callback, cb => {
|
|
1569
1577
|
const collection = this.$__collection;
|
|
1570
1578
|
|
|
1571
|
-
this.
|
|
1579
|
+
this.diffIndexes({ toCreate: false }, (err, res) => {
|
|
1572
1580
|
if (err != null) {
|
|
1573
1581
|
return cb(err);
|
|
1574
1582
|
}
|
|
1575
1583
|
|
|
1576
|
-
|
|
1577
|
-
const schemaIndexes = getRelatedSchemaIndexes(this, this.schema.indexes());
|
|
1578
|
-
|
|
1579
|
-
const toDrop = [];
|
|
1580
|
-
|
|
1581
|
-
for (const dbIndex of dbIndexes) {
|
|
1582
|
-
let found = false;
|
|
1583
|
-
// Never try to drop `_id` index, MongoDB server doesn't allow it
|
|
1584
|
-
if (isDefaultIdIndex(dbIndex)) {
|
|
1585
|
-
continue;
|
|
1586
|
-
}
|
|
1587
|
-
|
|
1588
|
-
for (const [schemaIndexKeysObject, schemaIndexOptions] of schemaIndexes) {
|
|
1589
|
-
const options = decorateDiscriminatorIndexOptions(this.schema, utils.clone(schemaIndexOptions));
|
|
1590
|
-
applySchemaCollation(schemaIndexKeysObject, options, this.schema.options);
|
|
1591
|
-
|
|
1592
|
-
if (isIndexEqual(schemaIndexKeysObject, options, dbIndex)) {
|
|
1593
|
-
found = true;
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
if (!found) {
|
|
1598
|
-
toDrop.push(dbIndex.name);
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1584
|
+
const toDrop = res.toDrop;
|
|
1601
1585
|
|
|
1602
1586
|
if (toDrop.length === 0) {
|
|
1603
1587
|
return cb(null, []);
|
|
@@ -3581,6 +3565,7 @@ function _setIsNew(doc, val) {
|
|
|
3581
3565
|
* @param {String|number} [options.w=1] The [write concern](https://docs.mongodb.com/manual/reference/write-concern/). See [`Query#w()`](/docs/api.html#query_Query-w) for more information.
|
|
3582
3566
|
* @param {number} [options.wtimeout=null] The [write concern timeout](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout).
|
|
3583
3567
|
* @param {Boolean} [options.j=true] If false, disable [journal acknowledgement](https://docs.mongodb.com/manual/reference/write-concern/#j-option)
|
|
3568
|
+
* @param {Boolean} [options.skipValidation=false] Set to true to skip Mongoose schema validation on bulk write operations. Mongoose currently runs validation on `insertOne` and `replaceOne` operations by default.
|
|
3584
3569
|
* @param {Boolean} [options.bypassDocumentValidation=false] If true, disable [MongoDB server-side schema validation](https://docs.mongodb.com/manual/core/schema-validation/) for all writes in this bulk.
|
|
3585
3570
|
* @param {Boolean} [options.strict=null] Overwrites the [`strict` option](/docs/guide.html#strict) on schema. If false, allows filtering and writing fields not defined in the schema for all writes in this bulk.
|
|
3586
3571
|
* @param {Function} [callback] callback `function(error, bulkWriteOpResult) {}`
|
|
@@ -4574,9 +4559,9 @@ function populate(model, docs, options, callback) {
|
|
|
4574
4559
|
}
|
|
4575
4560
|
// If no models to populate but we have a nested populate,
|
|
4576
4561
|
// keep trying, re: gh-8946
|
|
4577
|
-
if (
|
|
4578
|
-
const opts = utils.populate(
|
|
4579
|
-
path:
|
|
4562
|
+
if (populateOptions.populate != null) {
|
|
4563
|
+
const opts = utils.populate(populateOptions.populate).map(pop => Object.assign({}, pop, {
|
|
4564
|
+
path: populateOptions.path + '.' + pop.path
|
|
4580
4565
|
}));
|
|
4581
4566
|
return model.populate(docs, opts, callback);
|
|
4582
4567
|
}
|
package/lib/query.js
CHANGED
|
@@ -4610,7 +4610,10 @@ Query.prototype.transform = function(fn) {
|
|
|
4610
4610
|
* // Throws if no doc returned
|
|
4611
4611
|
* await Model.findOne({ foo: 'bar' }).orFail();
|
|
4612
4612
|
*
|
|
4613
|
-
* // Throws if no document was updated
|
|
4613
|
+
* // Throws if no document was updated. Note that `orFail()` will still
|
|
4614
|
+
* // throw if the only document that matches is `{ foo: 'bar', name: 'test' }`,
|
|
4615
|
+
* // because `orFail()` will throw if no document was _updated_, not
|
|
4616
|
+
* // if no document was _found_.
|
|
4614
4617
|
* await Model.updateOne({ foo: 'bar' }, { name: 'test' }).orFail();
|
|
4615
4618
|
*
|
|
4616
4619
|
* // Throws "No docs found!" error if no docs match `{ foo: 'bar' }`
|
|
@@ -4977,7 +4980,7 @@ function castQuery(query) {
|
|
|
4977
4980
|
* a response for each query has also been returned, the results are passed to
|
|
4978
4981
|
* the callback.
|
|
4979
4982
|
*
|
|
4980
|
-
* @param {Object|String} path either the path to populate or an object specifying all parameters
|
|
4983
|
+
* @param {Object|String|Array<String>} path either the path(s) to populate or an object specifying all parameters
|
|
4981
4984
|
* @param {Object|String} [select] Field selection for the population query
|
|
4982
4985
|
* @param {Model} [model] The model you wish to use for population. If not specified, populate will look up the model by the name in the Schema's `ref` field.
|
|
4983
4986
|
* @param {Object} [match] Conditions for the population query
|
package/lib/queryhelpers.js
CHANGED
|
@@ -226,7 +226,9 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
226
226
|
const addedPaths = [];
|
|
227
227
|
schema.eachPath(function(path, type) {
|
|
228
228
|
if (prefix) path = prefix + '.' + path;
|
|
229
|
-
|
|
229
|
+
if (type.$isSchemaMap || path.endsWith('.$*')) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
230
232
|
let addedPath = analyzePath(path, type);
|
|
231
233
|
// arrays
|
|
232
234
|
if (addedPath == null && !Array.isArray(type) && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
|
|
@@ -248,7 +250,6 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
248
250
|
}
|
|
249
251
|
}
|
|
250
252
|
});
|
|
251
|
-
|
|
252
253
|
stack.pop();
|
|
253
254
|
return addedPaths;
|
|
254
255
|
}
|