mongoose 6.3.1 → 6.3.4
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/CHANGELOG.md +7300 -0
- package/History.md +1 -0
- package/README.md +2 -2
- package/dist/browser.umd.js +1 -1
- package/lib/connection.js +2 -1
- package/lib/document.js +59 -59
- package/lib/error/cast.js +2 -1
- package/lib/helpers/clone.js +2 -1
- package/lib/helpers/common.js +0 -8
- package/lib/helpers/immediate.js +3 -1
- package/lib/helpers/isAsyncFunction.js +19 -7
- package/lib/helpers/model/castBulkWrite.js +12 -0
- package/lib/helpers/query/cast$expr.js +4 -1
- package/lib/index.js +1 -1
- package/lib/internal.js +0 -1
- package/lib/model.js +49 -59
- package/lib/query.js +7 -3
- package/lib/queryhelpers.js +3 -2
- package/lib/schema/SubdocumentPath.js +3 -15
- package/lib/schema/documentarray.js +5 -3
- package/lib/schema/number.js +1 -5
- package/lib/schema/objectid.js +2 -4
- package/lib/schema/string.js +3 -6
- package/lib/schema.js +9 -0
- package/lib/types/DocumentArray/methods/index.js +8 -0
- package/lib/utils.js +4 -0
- package/package.json +39 -19
- package/tsconfig.json +1 -2
- package/types/aggregate.d.ts +1 -2
- package/types/connection.d.ts +3 -4
- package/types/cursor.d.ts +3 -2
- package/types/document.d.ts +15 -12
- package/types/error.d.ts +124 -124
- package/types/index.d.ts +173 -147
- package/types/mongooseoptions.d.ts +1 -2
- package/types/schemaoptions.d.ts +1 -2
package/lib/connection.js
CHANGED
|
@@ -1357,7 +1357,8 @@ Connection.prototype.optionsProvideAuthenticationData = function(options) {
|
|
|
1357
1357
|
* that this connection uses to talk to MongoDB.
|
|
1358
1358
|
*
|
|
1359
1359
|
* #### Example:
|
|
1360
|
-
* const conn = await mongoose.createConnection('mongodb://localhost:27017/test')
|
|
1360
|
+
* const conn = await mongoose.createConnection('mongodb://localhost:27017/test').
|
|
1361
|
+
* asPromise();
|
|
1361
1362
|
*
|
|
1362
1363
|
* conn.getClient(); // MongoClient { ... }
|
|
1363
1364
|
*
|
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
|
|
|
@@ -1455,14 +1460,18 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1455
1460
|
}
|
|
1456
1461
|
|
|
1457
1462
|
if (shouldSet) {
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
if (
|
|
1465
|
-
|
|
1463
|
+
let savedState = null;
|
|
1464
|
+
let savedStatePath = null;
|
|
1465
|
+
if (!constructing) {
|
|
1466
|
+
const doc = this.$isSubdocument ? this.ownerDocument() : this;
|
|
1467
|
+
savedState = doc.$__.savedState;
|
|
1468
|
+
savedStatePath = this.$isSubdocument ? this.$__.fullPath + '.' + path : path;
|
|
1469
|
+
if (savedState != null) {
|
|
1470
|
+
const firstDot = savedStatePath.indexOf('.');
|
|
1471
|
+
const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
|
|
1472
|
+
if (!savedState.hasOwnProperty(topLevelPath)) {
|
|
1473
|
+
savedState[topLevelPath] = utils.clone(doc.$__getValue(topLevelPath));
|
|
1474
|
+
}
|
|
1466
1475
|
}
|
|
1467
1476
|
}
|
|
1468
1477
|
|
|
@@ -1619,7 +1628,6 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1619
1628
|
|
|
1620
1629
|
const shouldModify = this.$__shouldModify(pathToMark, path, options, constructing, parts,
|
|
1621
1630
|
schema, val, priorVal);
|
|
1622
|
-
const _this = this;
|
|
1623
1631
|
|
|
1624
1632
|
if (shouldModify) {
|
|
1625
1633
|
this.markModified(pathToMark);
|
|
@@ -1635,14 +1643,6 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1635
1643
|
item && item.__parentArray && (item.__parentArray = val);
|
|
1636
1644
|
});
|
|
1637
1645
|
}
|
|
1638
|
-
|
|
1639
|
-
// Small hack for gh-1638: if we're overwriting the entire array, ignore
|
|
1640
|
-
// paths that were modified before the array overwrite
|
|
1641
|
-
this.$__.activePaths.forEach(function(modifiedPath) {
|
|
1642
|
-
if (modifiedPath.startsWith(path + '.')) {
|
|
1643
|
-
_this.$__.activePaths.ignore(modifiedPath);
|
|
1644
|
-
}
|
|
1645
|
-
});
|
|
1646
1646
|
}
|
|
1647
1647
|
} else if (Array.isArray(val) && Array.isArray(priorVal) && utils.isMongooseArray(val) && utils.isMongooseArray(priorVal)) {
|
|
1648
1648
|
val[arrayAtomicsSymbol] = priorVal[arrayAtomicsSymbol];
|
|
@@ -1833,7 +1833,6 @@ Document.prototype.$__path = function(path) {
|
|
|
1833
1833
|
*/
|
|
1834
1834
|
|
|
1835
1835
|
Document.prototype.markModified = function(path, scope) {
|
|
1836
|
-
// console.log('MarkModified', path, new Error().stack);
|
|
1837
1836
|
this.$__.activePaths.modify(path);
|
|
1838
1837
|
if (scope != null && !this.$isSubdocument) {
|
|
1839
1838
|
this.$__.pathsToScopes = this.$__pathsToScopes || {};
|
|
@@ -2525,9 +2524,11 @@ function _getPathsToValidate(doc) {
|
|
|
2525
2524
|
// the children as well
|
|
2526
2525
|
for (const path of paths) {
|
|
2527
2526
|
const _pathType = doc.$__schema.path(path);
|
|
2527
|
+
if (!_pathType) {
|
|
2528
|
+
continue;
|
|
2529
|
+
}
|
|
2528
2530
|
|
|
2529
|
-
if (!_pathType ||
|
|
2530
|
-
!_pathType.$isMongooseArray ||
|
|
2531
|
+
if (!_pathType.$isMongooseArray ||
|
|
2531
2532
|
// To avoid potential performance issues, skip doc arrays whose children
|
|
2532
2533
|
// are not required. `getPositionalPathType()` may be slow, so avoid
|
|
2533
2534
|
// it unless we have a case of #6364
|
|
@@ -2539,8 +2540,7 @@ function _getPathsToValidate(doc) {
|
|
|
2539
2540
|
|
|
2540
2541
|
// gh-11380: optimization. If the array isn't a document array and there's no validators
|
|
2541
2542
|
// on the array type, there's no need to run validation on the individual array elements.
|
|
2542
|
-
if (_pathType &&
|
|
2543
|
-
_pathType.$isMongooseArray &&
|
|
2543
|
+
if (_pathType.$isMongooseArray &&
|
|
2544
2544
|
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
|
2545
2545
|
!_pathType.$embeddedSchemaType.$isMongooseArray && // and arrays of arrays
|
|
2546
2546
|
_pathType.$embeddedSchemaType.validators.length === 0) {
|
|
@@ -3132,48 +3132,48 @@ Document.prototype.$isValid = function(path) {
|
|
|
3132
3132
|
|
|
3133
3133
|
Document.prototype.$__reset = function reset() {
|
|
3134
3134
|
let _this = this;
|
|
3135
|
-
DocumentArray || (DocumentArray = require('./types/DocumentArray'));
|
|
3136
3135
|
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
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();
|
|
3150
3160
|
}
|
|
3151
|
-
doc.$__reset();
|
|
3152
3161
|
}
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3153
3164
|
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
map('init', 'modify', function(i) {
|
|
3162
|
-
return _this.$__getValue(i);
|
|
3163
|
-
}).
|
|
3164
|
-
filter(function(val) {
|
|
3165
|
-
return val && !Array.isArray(val) && val.$isSingleNested;
|
|
3166
|
-
}).
|
|
3167
|
-
forEach(function(doc) {
|
|
3168
|
-
doc.$__reset();
|
|
3169
|
-
if (doc.$parent() === _this) {
|
|
3170
|
-
_this.$__.activePaths.init(doc.$basePath);
|
|
3171
|
-
} else if (doc.$parent() != null && doc.$parent().$isSubdocument) {
|
|
3172
|
-
// If map path underneath subdocument, may end up with a case where
|
|
3173
|
-
// map path is modified but parent still needs to be reset. See gh-10295
|
|
3174
|
-
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;
|
|
3175
3172
|
}
|
|
3176
|
-
}
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
return false;
|
|
3176
|
+
}
|
|
3177
3177
|
|
|
3178
3178
|
// clear atomics
|
|
3179
3179
|
this.$__dirty().forEach(function(dirt) {
|
package/lib/error/cast.js
CHANGED
|
@@ -142,7 +142,8 @@ function formatMessage(model, kind, stringValue, path, messageFormat, valueType,
|
|
|
142
142
|
}
|
|
143
143
|
if (reason != null &&
|
|
144
144
|
typeof reason.constructor === 'function' &&
|
|
145
|
-
reason.constructor.name !== 'AssertionError'
|
|
145
|
+
reason.constructor.name !== 'AssertionError' &&
|
|
146
|
+
reason.constructor.name !== 'Error') {
|
|
146
147
|
ret += ' because of "' + reason.constructor.name + '"';
|
|
147
148
|
}
|
|
148
149
|
return ret;
|
package/lib/helpers/clone.js
CHANGED
|
@@ -118,6 +118,7 @@ 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;
|
|
121
122
|
const ret = {};
|
|
122
123
|
let hasKeys;
|
|
123
124
|
|
|
@@ -138,7 +139,7 @@ function cloneObject(obj, options, isArrayChild) {
|
|
|
138
139
|
// Don't pass `isArrayChild` down
|
|
139
140
|
const val = clone(obj[key], options, false);
|
|
140
141
|
|
|
141
|
-
if (minimize === false && typeof val === 'undefined') {
|
|
142
|
+
if ((minimize === false || omitUndefined) && typeof val === 'undefined') {
|
|
142
143
|
delete ret[key];
|
|
143
144
|
} else if (minimize !== true || (typeof val !== 'undefined')) {
|
|
144
145
|
hasKeys || (hasKeys = true);
|
package/lib/helpers/common.js
CHANGED
|
@@ -80,14 +80,6 @@ function modifiedPaths(update, path, result) {
|
|
|
80
80
|
|
|
81
81
|
const _path = path + key;
|
|
82
82
|
result[_path] = true;
|
|
83
|
-
if (_path.indexOf('.') !== -1) {
|
|
84
|
-
const sp = _path.split('.');
|
|
85
|
-
let cur = sp[0];
|
|
86
|
-
for (let i = 1; i < sp.length; ++i) {
|
|
87
|
-
result[cur] = true;
|
|
88
|
-
cur += '.' + sp[i];
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
83
|
if (!Buffer.isBuffer(val) && isMongooseObject(val)) {
|
|
92
84
|
val = val.toObject({ transform: false, virtuals: false });
|
|
93
85
|
}
|
package/lib/helpers/immediate.js
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
const nextTick = process.nextTick
|
|
10
|
+
const nextTick = typeof process !== 'undefined' && typeof process.nextTick === 'function' ?
|
|
11
|
+
process.nextTick.bind(process) :
|
|
12
|
+
cb => setTimeout(cb, 0); // Fallback for browser build
|
|
11
13
|
|
|
12
14
|
module.exports = function immediate(cb) {
|
|
13
15
|
return nextTick(cb);
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
let asyncFunctionPrototype = null;
|
|
4
|
+
// try/catch for Babel compatibility, because Babel preset-env requires
|
|
5
|
+
// regenerator-runtime for async/await and we don't want to include that
|
|
6
|
+
// for a simple check.
|
|
7
|
+
try {
|
|
8
|
+
asyncFunctionPrototype = Object.getPrototypeOf(async function() {});
|
|
9
|
+
} catch (err) {}
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
if (asyncFunctionPrototype == null) {
|
|
12
|
+
module.exports = function isAsyncFunction() {
|
|
13
|
+
return false;
|
|
14
|
+
};
|
|
15
|
+
} else {
|
|
16
|
+
module.exports = function isAsyncFunction(v) {
|
|
17
|
+
return (
|
|
18
|
+
typeof v === 'function' &&
|
|
19
|
+
Object.getPrototypeOf(v) === asyncFunctionPrototype
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -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);
|
|
@@ -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
|
|
package/lib/index.js
CHANGED
|
@@ -267,7 +267,7 @@ Mongoose.prototype.get = Mongoose.prototype.set;
|
|
|
267
267
|
* @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
|
|
268
268
|
* @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
|
|
269
269
|
* @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
|
|
270
|
-
* @return {Connection} the created Connection object. Connections are not thenable, so you can
|
|
270
|
+
* @return {Connection} the created Connection object. Connections are not thenable, so you can't do `await mongoose.createConnection()`. To await use mongoose.createConnection(uri).asPromise() instead.
|
|
271
271
|
* @api public
|
|
272
272
|
*/
|
|
273
273
|
|
package/lib/internal.js
CHANGED
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);
|
|
@@ -1067,7 +1068,9 @@ Model.prototype.$__deleteOne = Model.prototype.$__remove;
|
|
|
1067
1068
|
* doc.model('User').findById(id, callback);
|
|
1068
1069
|
*
|
|
1069
1070
|
* @param {String} name model name
|
|
1071
|
+
* @method model
|
|
1070
1072
|
* @api public
|
|
1073
|
+
* @return {Model}
|
|
1071
1074
|
*/
|
|
1072
1075
|
|
|
1073
1076
|
Model.prototype.model = function model(name) {
|
|
@@ -1083,7 +1086,9 @@ Model.prototype.model = function model(name) {
|
|
|
1083
1086
|
* doc.model('User').findById(id, callback);
|
|
1084
1087
|
*
|
|
1085
1088
|
* @param {String} name model name
|
|
1089
|
+
* @method $model
|
|
1086
1090
|
* @api public
|
|
1091
|
+
* @return {Model}
|
|
1087
1092
|
*/
|
|
1088
1093
|
|
|
1089
1094
|
Model.prototype.$model = function $model(name) {
|
|
@@ -1484,61 +1489,68 @@ Model.syncIndexes = function syncIndexes(options, callback) {
|
|
|
1484
1489
|
* the result of this function would be the result of
|
|
1485
1490
|
* Model.syncIndexes().
|
|
1486
1491
|
*
|
|
1487
|
-
* @param {Object} options
|
|
1492
|
+
* @param {Object} [options]
|
|
1488
1493
|
* @param {Function} callback optional callback
|
|
1489
|
-
* @returns {Promise} which
|
|
1490
|
-
* 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.
|
|
1491
1496
|
*/
|
|
1492
1497
|
|
|
1493
1498
|
Model.diffIndexes = function diffIndexes(options, callback) {
|
|
1499
|
+
if (typeof options === 'function') {
|
|
1500
|
+
callback = options;
|
|
1501
|
+
options = null;
|
|
1502
|
+
}
|
|
1494
1503
|
const toDrop = [];
|
|
1495
1504
|
const toCreate = [];
|
|
1496
1505
|
callback = this.$handleCallbackError(callback);
|
|
1497
1506
|
return this.db.base._promiseOrCallback(callback, cb => {
|
|
1498
1507
|
cb = this.$wrapCallback(cb);
|
|
1499
|
-
this.listIndexes((err,
|
|
1500
|
-
if (
|
|
1501
|
-
|
|
1508
|
+
this.listIndexes((err, dbIndexes) => {
|
|
1509
|
+
if (dbIndexes === undefined) {
|
|
1510
|
+
dbIndexes = [];
|
|
1502
1511
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
for (const
|
|
1512
|
+
dbIndexes = getRelatedDBIndexes(this, dbIndexes);
|
|
1513
|
+
const schemaIndexes = getRelatedSchemaIndexes(this, this.schema.indexes());
|
|
1514
|
+
|
|
1515
|
+
for (const dbIndex of dbIndexes) {
|
|
1507
1516
|
let found = false;
|
|
1508
1517
|
// Never try to drop `_id` index, MongoDB server doesn't allow it
|
|
1509
|
-
if (isDefaultIdIndex(
|
|
1518
|
+
if (isDefaultIdIndex(dbIndex)) {
|
|
1510
1519
|
continue;
|
|
1511
1520
|
}
|
|
1512
1521
|
|
|
1513
|
-
for (const
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1516
|
-
|
|
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)) {
|
|
1517
1527
|
found = true;
|
|
1518
1528
|
}
|
|
1519
1529
|
}
|
|
1520
1530
|
|
|
1521
1531
|
if (!found) {
|
|
1522
|
-
toDrop.push(
|
|
1532
|
+
toDrop.push(dbIndex.name);
|
|
1523
1533
|
}
|
|
1524
1534
|
}
|
|
1525
1535
|
// Iterate through the indexes created on the schema and
|
|
1526
1536
|
// compare against the indexes in mongodb.
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
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
|
+
}
|
|
1534
1549
|
}
|
|
1535
|
-
if (
|
|
1536
|
-
|
|
1550
|
+
if (!found) {
|
|
1551
|
+
toCreate.push(key);
|
|
1537
1552
|
}
|
|
1538
1553
|
}
|
|
1539
|
-
if (!found) {
|
|
1540
|
-
toCreate.push(key);
|
|
1541
|
-
}
|
|
1542
1554
|
}
|
|
1543
1555
|
cb(null, { toDrop, toCreate });
|
|
1544
1556
|
});
|
|
@@ -1564,36 +1576,12 @@ Model.cleanIndexes = function cleanIndexes(callback) {
|
|
|
1564
1576
|
return this.db.base._promiseOrCallback(callback, cb => {
|
|
1565
1577
|
const collection = this.$__collection;
|
|
1566
1578
|
|
|
1567
|
-
this.
|
|
1579
|
+
this.diffIndexes({ toCreate: false }, (err, res) => {
|
|
1568
1580
|
if (err != null) {
|
|
1569
1581
|
return cb(err);
|
|
1570
1582
|
}
|
|
1571
1583
|
|
|
1572
|
-
|
|
1573
|
-
const schemaIndexes = getRelatedSchemaIndexes(this, this.schema.indexes());
|
|
1574
|
-
|
|
1575
|
-
const toDrop = [];
|
|
1576
|
-
|
|
1577
|
-
for (const dbIndex of dbIndexes) {
|
|
1578
|
-
let found = false;
|
|
1579
|
-
// Never try to drop `_id` index, MongoDB server doesn't allow it
|
|
1580
|
-
if (isDefaultIdIndex(dbIndex)) {
|
|
1581
|
-
continue;
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
for (const [schemaIndexKeysObject, schemaIndexOptions] of schemaIndexes) {
|
|
1585
|
-
const options = decorateDiscriminatorIndexOptions(this.schema, utils.clone(schemaIndexOptions));
|
|
1586
|
-
applySchemaCollation(schemaIndexKeysObject, options, this.schema.options);
|
|
1587
|
-
|
|
1588
|
-
if (isIndexEqual(schemaIndexKeysObject, options, dbIndex)) {
|
|
1589
|
-
found = true;
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
if (!found) {
|
|
1594
|
-
toDrop.push(dbIndex.name);
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1584
|
+
const toDrop = res.toDrop;
|
|
1597
1585
|
|
|
1598
1586
|
if (toDrop.length === 0) {
|
|
1599
1587
|
return cb(null, []);
|
|
@@ -3496,6 +3484,7 @@ function _setIsNew(doc, val) {
|
|
|
3496
3484
|
const subdocs = doc.$getAllSubdocs();
|
|
3497
3485
|
for (const subdoc of subdocs) {
|
|
3498
3486
|
subdoc.$isNew = val;
|
|
3487
|
+
subdoc.$emit('isNew', val);
|
|
3499
3488
|
}
|
|
3500
3489
|
}
|
|
3501
3490
|
|
|
@@ -3576,6 +3565,7 @@ function _setIsNew(doc, val) {
|
|
|
3576
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.
|
|
3577
3566
|
* @param {number} [options.wtimeout=null] The [write concern timeout](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout).
|
|
3578
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.
|
|
3579
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.
|
|
3580
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.
|
|
3581
3571
|
* @param {Function} [callback] callback `function(error, bulkWriteOpResult) {}`
|
|
@@ -4254,7 +4244,7 @@ Model.aggregate = function aggregate(pipeline, options, callback) {
|
|
|
4254
4244
|
* }
|
|
4255
4245
|
*
|
|
4256
4246
|
* @param {Object} obj
|
|
4257
|
-
* @param {Array} pathsToValidate
|
|
4247
|
+
* @param {Array|String} pathsToValidate
|
|
4258
4248
|
* @param {Object} [context]
|
|
4259
4249
|
* @param {Function} [callback]
|
|
4260
4250
|
* @return {Promise|undefined}
|
|
@@ -4273,7 +4263,7 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) {
|
|
|
4273
4263
|
let paths = Object.keys(schema.paths);
|
|
4274
4264
|
|
|
4275
4265
|
if (pathsToValidate != null) {
|
|
4276
|
-
const _pathsToValidate = new Set(pathsToValidate);
|
|
4266
|
+
const _pathsToValidate = typeof pathsToValidate === 'string' ? new Set(pathsToValidate.split(' ')) : new Set(pathsToValidate);
|
|
4277
4267
|
paths = paths.filter(p => {
|
|
4278
4268
|
const pieces = p.split('.');
|
|
4279
4269
|
let cur = pieces[0];
|
|
@@ -4569,9 +4559,9 @@ function populate(model, docs, options, callback) {
|
|
|
4569
4559
|
}
|
|
4570
4560
|
// If no models to populate but we have a nested populate,
|
|
4571
4561
|
// keep trying, re: gh-8946
|
|
4572
|
-
if (
|
|
4573
|
-
const opts = utils.populate(
|
|
4574
|
-
path:
|
|
4562
|
+
if (populateOptions.populate != null) {
|
|
4563
|
+
const opts = utils.populate(populateOptions.populate).map(pop => Object.assign({}, pop, {
|
|
4564
|
+
path: populateOptions.path + '.' + pop.path
|
|
4575
4565
|
}));
|
|
4576
4566
|
return model.populate(docs, opts, callback);
|
|
4577
4567
|
}
|
package/lib/query.js
CHANGED
|
@@ -53,6 +53,7 @@ const queryOptionMethods = new Set([
|
|
|
53
53
|
'maxScan',
|
|
54
54
|
'maxTimeMS',
|
|
55
55
|
'maxscan',
|
|
56
|
+
'populate',
|
|
56
57
|
'projection',
|
|
57
58
|
'read',
|
|
58
59
|
'select',
|
|
@@ -4609,7 +4610,10 @@ Query.prototype.transform = function(fn) {
|
|
|
4609
4610
|
* // Throws if no doc returned
|
|
4610
4611
|
* await Model.findOne({ foo: 'bar' }).orFail();
|
|
4611
4612
|
*
|
|
4612
|
-
* // 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_.
|
|
4613
4617
|
* await Model.updateOne({ foo: 'bar' }, { name: 'test' }).orFail();
|
|
4614
4618
|
*
|
|
4615
4619
|
* // Throws "No docs found!" error if no docs match `{ foo: 'bar' }`
|
|
@@ -4976,7 +4980,7 @@ function castQuery(query) {
|
|
|
4976
4980
|
* a response for each query has also been returned, the results are passed to
|
|
4977
4981
|
* the callback.
|
|
4978
4982
|
*
|
|
4979
|
-
* @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
|
|
4980
4984
|
* @param {Object|String} [select] Field selection for the population query
|
|
4981
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.
|
|
4982
4986
|
* @param {Object} [match] Conditions for the population query
|
|
@@ -5757,4 +5761,4 @@ Query.prototype.model;
|
|
|
5757
5761
|
* Export
|
|
5758
5762
|
*/
|
|
5759
5763
|
|
|
5760
|
-
module.exports = Query;
|
|
5764
|
+
module.exports = 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
|
}
|
|
@@ -60,25 +60,13 @@ function _createConstructor(schema, baseClass) {
|
|
|
60
60
|
Subdocument || (Subdocument = require('../types/subdocument'));
|
|
61
61
|
|
|
62
62
|
const _embedded = function SingleNested(value, path, parent) {
|
|
63
|
-
const _this = this;
|
|
64
|
-
|
|
65
63
|
this.$__parent = parent;
|
|
66
64
|
Subdocument.apply(this, arguments);
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (parent) {
|
|
71
|
-
parent.$on('save', function() {
|
|
72
|
-
_this.emit('save', _this);
|
|
73
|
-
_this.constructor.emit('save', _this);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
parent.$on('isNew', function(val) {
|
|
77
|
-
_this.isNew = val;
|
|
78
|
-
_this.emit('isNew', val);
|
|
79
|
-
_this.constructor.emit('isNew', val);
|
|
80
|
-
});
|
|
66
|
+
if (parent == null) {
|
|
67
|
+
return;
|
|
81
68
|
}
|
|
69
|
+
this.$session(parent.$session());
|
|
82
70
|
};
|
|
83
71
|
|
|
84
72
|
schema._preCompile();
|