mongoose 7.1.0 → 7.1.2
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/connection.js +0 -1
- package/lib/document.js +68 -29
- package/lib/drivers/node-mongodb-native/collection.js +7 -1
- package/lib/error/objectParameter.js +1 -1
- package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +2 -1
- package/lib/helpers/document/getDeepestSubdocumentForPath.js +38 -0
- package/lib/helpers/document/getEmbeddedDiscriminatorPath.js +5 -2
- package/lib/helpers/populate/getModelsMapForPopulate.js +1 -2
- package/lib/helpers/printJestWarning.js +15 -11
- package/lib/helpers/processConnectionOptions.js +4 -3
- package/lib/helpers/schema/getSubdocumentStrictValue.js +32 -0
- package/lib/helpers/timestamps/setupTimestamps.js +11 -7
- package/lib/query.js +41 -38
- package/lib/schema/DocumentArrayElement.js +100 -0
- package/lib/schema/SubdocumentPath.js +1 -0
- package/lib/schema/documentarray.js +5 -16
- package/lib/schema/string.js +1 -0
- package/lib/schema.js +27 -0
- package/lib/types/map.js +25 -11
- package/package.json +14 -12
- package/types/document.d.ts +7 -7
- package/types/index.d.ts +10 -3
- package/types/models.d.ts +98 -76
- package/types/query.d.ts +133 -41
package/lib/connection.js
CHANGED
|
@@ -825,7 +825,6 @@ async function _createMongoClient(conn, uri, options) {
|
|
|
825
825
|
options = processConnectionOptions(uri, options);
|
|
826
826
|
|
|
827
827
|
if (options) {
|
|
828
|
-
options = clone(options);
|
|
829
828
|
|
|
830
829
|
const autoIndex = options.config && options.config.autoIndex != null ?
|
|
831
830
|
options.config.autoIndex :
|
package/lib/document.js
CHANGED
|
@@ -26,6 +26,7 @@ const flattenObjectWithDottedPaths = require('./helpers/path/flattenObjectWithDo
|
|
|
26
26
|
const get = require('./helpers/get');
|
|
27
27
|
const getEmbeddedDiscriminatorPath = require('./helpers/document/getEmbeddedDiscriminatorPath');
|
|
28
28
|
const getKeysInSchemaOrder = require('./helpers/schema/getKeysInSchemaOrder');
|
|
29
|
+
const getSubdocumentStrictValue = require('./helpers/schema/getSubdocumentStrictValue');
|
|
29
30
|
const handleSpreadDoc = require('./helpers/document/handleSpreadDoc');
|
|
30
31
|
const immediate = require('./helpers/immediate');
|
|
31
32
|
const isDefiningProjection = require('./helpers/projection/isDefiningProjection');
|
|
@@ -52,6 +53,7 @@ const populateModelSymbol = require('./helpers/symbols').populateModelSymbol;
|
|
|
52
53
|
const scopeSymbol = require('./helpers/symbols').scopeSymbol;
|
|
53
54
|
const schemaMixedSymbol = require('./schema/symbols').schemaMixedSymbol;
|
|
54
55
|
const parentPaths = require('./helpers/path/parentPaths');
|
|
56
|
+
const getDeepestSubdocumentForPath = require('./helpers/document/getDeepestSubdocumentForPath');
|
|
55
57
|
|
|
56
58
|
let DocumentArray;
|
|
57
59
|
let MongooseArray;
|
|
@@ -1032,7 +1034,8 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1032
1034
|
let key;
|
|
1033
1035
|
let prefix;
|
|
1034
1036
|
|
|
1035
|
-
const
|
|
1037
|
+
const userSpecifiedStrict = options && 'strict' in options;
|
|
1038
|
+
let strict = userSpecifiedStrict
|
|
1036
1039
|
? options.strict
|
|
1037
1040
|
: this.$__.strictMode;
|
|
1038
1041
|
|
|
@@ -1140,8 +1143,20 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1140
1143
|
}
|
|
1141
1144
|
|
|
1142
1145
|
let pathType = this.$__schema.pathType(path);
|
|
1146
|
+
let parts = null;
|
|
1143
1147
|
if (pathType === 'adhocOrUndefined') {
|
|
1144
|
-
|
|
1148
|
+
parts = path.indexOf('.') === -1 ? [path] : path.split('.');
|
|
1149
|
+
pathType = getEmbeddedDiscriminatorPath(this, parts, { typeOnly: true });
|
|
1150
|
+
}
|
|
1151
|
+
if (pathType === 'adhocOrUndefined' && !userSpecifiedStrict) {
|
|
1152
|
+
// May be path underneath non-strict schema
|
|
1153
|
+
if (parts == null) {
|
|
1154
|
+
parts = path.indexOf('.') === -1 ? [path] : path.split('.');
|
|
1155
|
+
}
|
|
1156
|
+
const subdocStrict = getSubdocumentStrictValue(this.$__schema, parts);
|
|
1157
|
+
if (subdocStrict !== undefined) {
|
|
1158
|
+
strict = subdocStrict;
|
|
1159
|
+
}
|
|
1145
1160
|
}
|
|
1146
1161
|
|
|
1147
1162
|
// Assume this is a Mongoose document that was copied into a POJO using
|
|
@@ -1204,7 +1219,9 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1204
1219
|
}
|
|
1205
1220
|
|
|
1206
1221
|
let schema;
|
|
1207
|
-
|
|
1222
|
+
if (parts == null) {
|
|
1223
|
+
parts = path.indexOf('.') === -1 ? [path] : path.split('.');
|
|
1224
|
+
}
|
|
1208
1225
|
|
|
1209
1226
|
// Might need to change path for top-level alias
|
|
1210
1227
|
if (typeof this.$__schema.aliases[parts[0]] === 'string') {
|
|
@@ -1233,6 +1250,11 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1233
1250
|
// allow changes to sub paths of mixed types
|
|
1234
1251
|
mixed = true;
|
|
1235
1252
|
break;
|
|
1253
|
+
} else if (schema.$isSchemaMap && schema.$__schemaType instanceof MixedSchema && i < parts.length - 1) {
|
|
1254
|
+
// Map of mixed and not the last element in the path resolves to mixed
|
|
1255
|
+
mixed = true;
|
|
1256
|
+
schema = schema.$__schemaType;
|
|
1257
|
+
break;
|
|
1236
1258
|
}
|
|
1237
1259
|
}
|
|
1238
1260
|
|
|
@@ -1377,15 +1399,19 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1377
1399
|
didPopulate = true;
|
|
1378
1400
|
}
|
|
1379
1401
|
|
|
1380
|
-
if (
|
|
1402
|
+
if (!refMatches || !schema.$isSingleNested || !val.$__) {
|
|
1381
1403
|
// If this path is underneath a single nested schema, we'll call the setter
|
|
1382
1404
|
// later in `$__set()` because we don't take `_doc` when we iterate through
|
|
1383
1405
|
// a single nested doc. That's to make sure we get the correct context.
|
|
1384
1406
|
// Otherwise we would double-call the setter, see gh-7196.
|
|
1407
|
+
let setterContext = this;
|
|
1408
|
+
if (this.$__schema.singleNestedPaths[path] != null && parts.length > 1) {
|
|
1409
|
+
setterContext = getDeepestSubdocumentForPath(this, parts, this.schema);
|
|
1410
|
+
}
|
|
1385
1411
|
if (options != null && options.overwriteImmutable) {
|
|
1386
|
-
val = schema.applySetters(val,
|
|
1412
|
+
val = schema.applySetters(val, setterContext, false, priorVal, { overwriteImmutable: true });
|
|
1387
1413
|
} else {
|
|
1388
|
-
val = schema.applySetters(val,
|
|
1414
|
+
val = schema.applySetters(val, setterContext, false, priorVal);
|
|
1389
1415
|
}
|
|
1390
1416
|
}
|
|
1391
1417
|
|
|
@@ -1560,13 +1586,6 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru
|
|
|
1560
1586
|
return true;
|
|
1561
1587
|
}
|
|
1562
1588
|
|
|
1563
|
-
// Re: the note about gh-7196, `val` is the raw value without casting or
|
|
1564
|
-
// setters if the full path is under a single nested subdoc because we don't
|
|
1565
|
-
// want to double run setters. So don't set it as modified. See gh-7264.
|
|
1566
|
-
if (this.$__schema.singleNestedPaths[path] != null) {
|
|
1567
|
-
return false;
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
1589
|
if (val === void 0 && !this.$__isSelected(path)) {
|
|
1571
1590
|
// when a path is not selected in a query, its initial
|
|
1572
1591
|
// value will be undefined.
|
|
@@ -1674,17 +1693,26 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1674
1693
|
obj[parts[i]] = val;
|
|
1675
1694
|
}
|
|
1676
1695
|
} else {
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
obj =
|
|
1681
|
-
} else if (
|
|
1682
|
-
obj =
|
|
1683
|
-
} else if (
|
|
1684
|
-
obj =
|
|
1696
|
+
const isMap = obj instanceof Map;
|
|
1697
|
+
let value = isMap ? obj.get(parts[i]) : obj[parts[i]];
|
|
1698
|
+
if (utils.isPOJO(value)) {
|
|
1699
|
+
obj = value;
|
|
1700
|
+
} else if (value && value instanceof Embedded) {
|
|
1701
|
+
obj = value;
|
|
1702
|
+
} else if (value && !Array.isArray(value) && value.$isSingleNested) {
|
|
1703
|
+
obj = value._doc;
|
|
1704
|
+
} else if (value && Array.isArray(value)) {
|
|
1705
|
+
obj = value;
|
|
1706
|
+
} else if (value == null) {
|
|
1707
|
+
value = {};
|
|
1708
|
+
if (isMap) {
|
|
1709
|
+
obj.set(parts[i], value);
|
|
1710
|
+
} else {
|
|
1711
|
+
obj[parts[i]] = value;
|
|
1712
|
+
}
|
|
1713
|
+
obj = value;
|
|
1685
1714
|
} else {
|
|
1686
|
-
obj
|
|
1687
|
-
obj = obj[parts[i]];
|
|
1715
|
+
obj = value;
|
|
1688
1716
|
}
|
|
1689
1717
|
}
|
|
1690
1718
|
}
|
|
@@ -1764,7 +1792,11 @@ Document.prototype.$inc = function $inc(path, val) {
|
|
|
1764
1792
|
|
|
1765
1793
|
if (shouldSet) {
|
|
1766
1794
|
this.$__.primitiveAtomics = this.$__.primitiveAtomics || {};
|
|
1767
|
-
this.$__.primitiveAtomics[path]
|
|
1795
|
+
if (this.$__.primitiveAtomics[path] == null) {
|
|
1796
|
+
this.$__.primitiveAtomics[path] = { $inc: valToInc };
|
|
1797
|
+
} else {
|
|
1798
|
+
this.$__.primitiveAtomics[path].$inc += valToInc;
|
|
1799
|
+
}
|
|
1768
1800
|
this.markModified(path);
|
|
1769
1801
|
this.$__setValue(path, valToSet);
|
|
1770
1802
|
}
|
|
@@ -2181,19 +2213,26 @@ Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
|
|
|
2181
2213
|
|
|
2182
2214
|
Document.prototype.isModified = function(paths, modifiedPaths) {
|
|
2183
2215
|
if (paths) {
|
|
2184
|
-
const directModifiedPaths = Object.keys(this.$__.activePaths.getStatePaths('modify'));
|
|
2185
|
-
if (directModifiedPaths.length === 0) {
|
|
2186
|
-
return false;
|
|
2187
|
-
}
|
|
2188
|
-
|
|
2189
2216
|
if (!Array.isArray(paths)) {
|
|
2190
2217
|
paths = paths.indexOf(' ') === -1 ? [paths] : paths.split(' ');
|
|
2191
2218
|
}
|
|
2219
|
+
|
|
2220
|
+
const directModifiedPathsObj = this.$__.activePaths.states.modify;
|
|
2221
|
+
if (directModifiedPathsObj == null) {
|
|
2222
|
+
return false;
|
|
2223
|
+
}
|
|
2224
|
+
for (const path of paths) {
|
|
2225
|
+
if (Object.prototype.hasOwnProperty.call(directModifiedPathsObj, path)) {
|
|
2226
|
+
return true;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2192
2230
|
const modified = modifiedPaths || this[documentModifiedPaths]();
|
|
2193
2231
|
const isModifiedChild = paths.some(function(path) {
|
|
2194
2232
|
return !!~modified.indexOf(path);
|
|
2195
2233
|
});
|
|
2196
2234
|
|
|
2235
|
+
const directModifiedPaths = Object.keys(directModifiedPathsObj);
|
|
2197
2236
|
return isModifiedChild || paths.some(function(path) {
|
|
2198
2237
|
return directModifiedPaths.some(function(mod) {
|
|
2199
2238
|
return mod === path || path.startsWith(mod + '.');
|
|
@@ -208,8 +208,14 @@ function iter(i) {
|
|
|
208
208
|
|
|
209
209
|
if (debug) {
|
|
210
210
|
if (typeof debug === 'function') {
|
|
211
|
+
let argsToAdd = null;
|
|
212
|
+
if (typeof args[args.length - 1] == 'function') {
|
|
213
|
+
argsToAdd = args.slice(0, args.length - 1);
|
|
214
|
+
} else {
|
|
215
|
+
argsToAdd = args;
|
|
216
|
+
}
|
|
211
217
|
debug.apply(_this,
|
|
212
|
-
[_this.name, i].concat(
|
|
218
|
+
[_this.name, i].concat(argsToAdd));
|
|
213
219
|
} else if (debug instanceof stream.Writable) {
|
|
214
220
|
this.$printToStream(_this.name, i, args, debug);
|
|
215
221
|
} else {
|
|
@@ -18,7 +18,7 @@ class ObjectParameterError extends MongooseError {
|
|
|
18
18
|
*/
|
|
19
19
|
constructor(value, paramName, fnName) {
|
|
20
20
|
super('Parameter "' + paramName + '" to ' + fnName +
|
|
21
|
-
'() must be an object, got ' + value.toString());
|
|
21
|
+
'() must be an object, got "' + value.toString() + '" (type ' + typeof value + ')');
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -55,7 +55,8 @@ module.exports = function mergeDiscriminatorSchema(to, from, path, seen) {
|
|
|
55
55
|
// base schema has a given path as a single nested but discriminator schema
|
|
56
56
|
// has the path as a document array, or vice versa (gh-9534)
|
|
57
57
|
if ((from[key].$isSingleNested && to[key].$isMongooseDocumentArray) ||
|
|
58
|
-
(from[key].$isMongooseDocumentArray && to[key].$isSingleNested)
|
|
58
|
+
(from[key].$isMongooseDocumentArray && to[key].$isSingleNested) ||
|
|
59
|
+
(from[key].$isMongooseDocumentArrayElement && to[key].$isMongooseDocumentArrayElement)) {
|
|
59
60
|
continue;
|
|
60
61
|
} else if (from[key].instanceOfSchema) {
|
|
61
62
|
if (to[key].instanceOfSchema) {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Find the deepest subdocument along a given path to ensure setter functions run
|
|
5
|
+
* with the correct subdocument as `this`. If no subdocuments, returns the top-level
|
|
6
|
+
* document.
|
|
7
|
+
*
|
|
8
|
+
* @param {Document} doc
|
|
9
|
+
* @param {String[]} parts
|
|
10
|
+
* @param {Schema} schema
|
|
11
|
+
* @returns Document
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
module.exports = function getDeepestSubdocumentForPath(doc, parts, schema) {
|
|
15
|
+
let curPath = parts[0];
|
|
16
|
+
let curSchema = schema;
|
|
17
|
+
let subdoc = doc;
|
|
18
|
+
for (let i = 0; i < parts.length - 1; ++i) {
|
|
19
|
+
const curSchemaType = curSchema.path(curPath);
|
|
20
|
+
if (curSchemaType && curSchemaType.schema) {
|
|
21
|
+
let newSubdoc = subdoc.get(curPath);
|
|
22
|
+
curSchema = curSchemaType.schema;
|
|
23
|
+
curPath = parts[i + 1];
|
|
24
|
+
if (Array.isArray(newSubdoc) && !isNaN(curPath)) {
|
|
25
|
+
newSubdoc = newSubdoc[curPath];
|
|
26
|
+
curPath = '';
|
|
27
|
+
}
|
|
28
|
+
if (newSubdoc == null) {
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
subdoc = newSubdoc;
|
|
32
|
+
} else {
|
|
33
|
+
curPath += curPath.length ? '.' + parts[i + 1] : parts[i + 1];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return subdoc;
|
|
38
|
+
};
|
|
@@ -6,8 +6,9 @@ const getSchemaDiscriminatorByValue = require('../discriminator/getSchemaDiscrim
|
|
|
6
6
|
/**
|
|
7
7
|
* Like `schema.path()`, except with a document, because impossible to
|
|
8
8
|
* determine path type without knowing the embedded discriminator key.
|
|
9
|
+
*
|
|
9
10
|
* @param {Document} doc
|
|
10
|
-
* @param {String} path
|
|
11
|
+
* @param {String|String[]} path
|
|
11
12
|
* @param {Object} [options]
|
|
12
13
|
* @api private
|
|
13
14
|
*/
|
|
@@ -15,7 +16,9 @@ const getSchemaDiscriminatorByValue = require('../discriminator/getSchemaDiscrim
|
|
|
15
16
|
module.exports = function getEmbeddedDiscriminatorPath(doc, path, options) {
|
|
16
17
|
options = options || {};
|
|
17
18
|
const typeOnly = options.typeOnly;
|
|
18
|
-
const parts =
|
|
19
|
+
const parts = Array.isArray(path) ?
|
|
20
|
+
path :
|
|
21
|
+
(path.indexOf('.') === -1 ? [path] : path.split('.'));
|
|
19
22
|
let schemaType = null;
|
|
20
23
|
let type = 'adhocOrUndefined';
|
|
21
24
|
|
|
@@ -389,8 +389,7 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
|
|
|
389
389
|
let foreignField = virtual.options.foreignField;
|
|
390
390
|
|
|
391
391
|
if (!localField || !foreignField) {
|
|
392
|
-
return new MongooseError(
|
|
393
|
-
'localField and foreignField options');
|
|
392
|
+
return new MongooseError(`Cannot populate virtual \`${options.path}\` on model \`${model.modelName}\`, because options \`localField\` and / or \`foreignField\` are missing`);
|
|
394
393
|
}
|
|
395
394
|
|
|
396
395
|
if (typeof localField === 'function') {
|
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
const utils = require('../utils');
|
|
4
4
|
|
|
5
|
-
if (typeof jest !== 'undefined' &&
|
|
6
|
-
|
|
7
|
-
'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
if (typeof jest !== 'undefined' && !process.env.SUPPRESS_JEST_WARNINGS) {
|
|
6
|
+
if (typeof window !== 'undefined') {
|
|
7
|
+
utils.warn('Mongoose: looks like you\'re trying to test a Mongoose app ' +
|
|
8
|
+
'with Jest\'s default jsdom test environment. Please make sure you read ' +
|
|
9
|
+
'Mongoose\'s docs on configuring Jest to test Node.js apps: ' +
|
|
10
|
+
'https://mongoosejs.com/docs/jest.html. Set the SUPPRESS_JEST_WARNINGS to true ' +
|
|
11
|
+
'to hide this warning.');
|
|
12
|
+
}
|
|
11
13
|
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
if (setTimeout.clock != null && typeof setTimeout.clock.Date === 'function') {
|
|
15
|
+
utils.warn('Mongoose: looks like you\'re trying to test a Mongoose app ' +
|
|
16
|
+
'with Jest\'s mock timers enabled. Please make sure you read ' +
|
|
17
|
+
'Mongoose\'s docs on configuring Jest to test Node.js apps: ' +
|
|
18
|
+
'https://mongoosejs.com/docs/jest.html. Set the SUPPRESS_JEST_WARNINGS to true ' +
|
|
19
|
+
'to hide this warning.');
|
|
20
|
+
}
|
|
17
21
|
}
|
|
@@ -9,11 +9,12 @@ function processConnectionOptions(uri, options) {
|
|
|
9
9
|
? opts.readPreference
|
|
10
10
|
: getUriReadPreference(uri);
|
|
11
11
|
|
|
12
|
+
const clonedOpts = clone(opts);
|
|
12
13
|
const resolvedOpts = (readPreference && readPreference !== 'primary' && readPreference !== 'primaryPreferred')
|
|
13
|
-
? resolveOptsConflicts(readPreference,
|
|
14
|
-
:
|
|
14
|
+
? resolveOptsConflicts(readPreference, clonedOpts)
|
|
15
|
+
: clonedOpts;
|
|
15
16
|
|
|
16
|
-
return
|
|
17
|
+
return resolvedOpts;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function resolveOptsConflicts(pref, opts) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Find the `strict` mode setting for the deepest subdocument along a given path
|
|
5
|
+
* to ensure we have the correct default value for `strict`. When setting values
|
|
6
|
+
* underneath a subdocument, we should use the subdocument's `strict` setting by
|
|
7
|
+
* default, not the top-level document's.
|
|
8
|
+
*
|
|
9
|
+
* @param {Schema} schema
|
|
10
|
+
* @param {String[]} parts
|
|
11
|
+
* @returns {boolean | 'throw' | undefined}
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
module.exports = function getSubdocumentStrictValue(schema, parts) {
|
|
15
|
+
if (parts.length === 1) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
let cur = parts[0];
|
|
19
|
+
let strict = undefined;
|
|
20
|
+
for (let i = 0; i < parts.length - 1; ++i) {
|
|
21
|
+
const curSchemaType = schema.path(cur);
|
|
22
|
+
if (curSchemaType && curSchemaType.schema) {
|
|
23
|
+
strict = curSchemaType.schema.options.strict;
|
|
24
|
+
schema = curSchemaType.schema;
|
|
25
|
+
cur = curSchemaType.$isMongooseDocumentArray && !isNaN(parts[i + 1]) ? '' : parts[i + 1];
|
|
26
|
+
} else {
|
|
27
|
+
cur += cur.length ? ('.' + parts[i + 1]) : parts[i + 1];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return strict;
|
|
32
|
+
};
|
|
@@ -18,11 +18,9 @@ module.exports = function setupTimestamps(schema, timestamps) {
|
|
|
18
18
|
const ts = s.schema.options.timestamps;
|
|
19
19
|
return !!ts;
|
|
20
20
|
}
|
|
21
|
-
|
|
22
21
|
if (!timestamps && !childHasTimestamp) {
|
|
23
22
|
return;
|
|
24
23
|
}
|
|
25
|
-
|
|
26
24
|
const createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
27
25
|
const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
28
26
|
const currentTime = timestamps != null && timestamps.hasOwnProperty('currentTime') ?
|
|
@@ -57,15 +55,15 @@ module.exports = function setupTimestamps(schema, timestamps) {
|
|
|
57
55
|
|
|
58
56
|
schema.methods.initializeTimestamps = function() {
|
|
59
57
|
const ts = currentTime != null ?
|
|
60
|
-
currentTime() :
|
|
61
|
-
|
|
58
|
+
currentTime() : this.constructor.base.now();
|
|
59
|
+
|
|
60
|
+
|
|
62
61
|
if (createdAt && !this.get(createdAt)) {
|
|
63
62
|
this.$set(createdAt, ts);
|
|
64
63
|
}
|
|
65
64
|
if (updatedAt && !this.get(updatedAt)) {
|
|
66
65
|
this.$set(updatedAt, ts);
|
|
67
66
|
}
|
|
68
|
-
|
|
69
67
|
if (this.$isSubdocument) {
|
|
70
68
|
return this;
|
|
71
69
|
}
|
|
@@ -98,8 +96,14 @@ module.exports = function setupTimestamps(schema, timestamps) {
|
|
|
98
96
|
if (replaceOps.has(this.op) && this.getUpdate() == null) {
|
|
99
97
|
this.setUpdate({});
|
|
100
98
|
}
|
|
101
|
-
applyTimestampsToUpdate(
|
|
102
|
-
|
|
99
|
+
applyTimestampsToUpdate(
|
|
100
|
+
now,
|
|
101
|
+
createdAt,
|
|
102
|
+
updatedAt,
|
|
103
|
+
this.getUpdate(),
|
|
104
|
+
this._mongooseOptions,
|
|
105
|
+
this.schema
|
|
106
|
+
);
|
|
103
107
|
applyTimestampsToChildren(now, this.getUpdate(), this.model.schema);
|
|
104
108
|
next();
|
|
105
109
|
}
|
package/lib/query.js
CHANGED
|
@@ -1606,7 +1606,14 @@ Query.prototype.setOptions = function(options, overwrite) {
|
|
|
1606
1606
|
this._mongooseOptions.sanitizeFilter = options.sanitizeFilter;
|
|
1607
1607
|
delete options.sanitizeFilter;
|
|
1608
1608
|
}
|
|
1609
|
-
|
|
1609
|
+
if ('overwrite' in options) {
|
|
1610
|
+
this._mongooseOptions.overwrite = options.overwrite;
|
|
1611
|
+
delete options.overwrite;
|
|
1612
|
+
}
|
|
1613
|
+
if ('timestamps' in options) {
|
|
1614
|
+
this._mongooseOptions.timestamps = options.timestamps;
|
|
1615
|
+
delete options.timestamps;
|
|
1616
|
+
}
|
|
1610
1617
|
if ('defaults' in options) {
|
|
1611
1618
|
this._mongooseOptions.defaults = options.defaults;
|
|
1612
1619
|
// deleting options.defaults will cause 7287 to fail
|
|
@@ -1864,7 +1871,7 @@ Query.prototype._updateForExec = function() {
|
|
|
1864
1871
|
while (i--) {
|
|
1865
1872
|
const op = ops[i];
|
|
1866
1873
|
|
|
1867
|
-
if (this.
|
|
1874
|
+
if (this._mongooseOptions.overwrite) {
|
|
1868
1875
|
ret[op] = update[op];
|
|
1869
1876
|
continue;
|
|
1870
1877
|
}
|
|
@@ -1960,9 +1967,13 @@ Query.prototype._optionsForExec = function(model) {
|
|
|
1960
1967
|
}
|
|
1961
1968
|
}
|
|
1962
1969
|
|
|
1963
|
-
|
|
1964
|
-
if (
|
|
1965
|
-
|
|
1970
|
+
this._applyPaths();
|
|
1971
|
+
if (this._fields != null) {
|
|
1972
|
+
this._fields = this._castFields(this._fields);
|
|
1973
|
+
const projection = this._fieldsForExec();
|
|
1974
|
+
if (projection != null) {
|
|
1975
|
+
options.projection = projection;
|
|
1976
|
+
}
|
|
1966
1977
|
}
|
|
1967
1978
|
|
|
1968
1979
|
return options;
|
|
@@ -2211,10 +2222,6 @@ Query.prototype._find = async function _find() {
|
|
|
2211
2222
|
throw this.error();
|
|
2212
2223
|
}
|
|
2213
2224
|
|
|
2214
|
-
this._applyPaths();
|
|
2215
|
-
this._fields = this._castFields(this._fields);
|
|
2216
|
-
|
|
2217
|
-
const fields = this._fieldsForExec();
|
|
2218
2225
|
const mongooseOptions = this._mongooseOptions;
|
|
2219
2226
|
const _this = this;
|
|
2220
2227
|
const userProvidedFields = _this._userProvidedFields || {};
|
|
@@ -2230,8 +2237,8 @@ Query.prototype._find = async function _find() {
|
|
|
2230
2237
|
});
|
|
2231
2238
|
|
|
2232
2239
|
const options = this._optionsForExec();
|
|
2233
|
-
options.projection = this._fieldsForExec();
|
|
2234
2240
|
const filter = this._conditions;
|
|
2241
|
+
const fields = options.projection;
|
|
2235
2242
|
|
|
2236
2243
|
const cursor = await this._collection.collection.find(filter, options);
|
|
2237
2244
|
if (options.explain) {
|
|
@@ -2474,8 +2481,6 @@ Query.prototype._findOne = async function _findOne() {
|
|
|
2474
2481
|
throw err;
|
|
2475
2482
|
}
|
|
2476
2483
|
|
|
2477
|
-
this._applyPaths();
|
|
2478
|
-
this._fields = this._castFields(this._fields);
|
|
2479
2484
|
applyGlobalMaxTimeMS(this.options, this.model);
|
|
2480
2485
|
applyGlobalDiskUse(this.options, this.model);
|
|
2481
2486
|
|
|
@@ -3146,8 +3151,8 @@ function prepareDiscriminatorCriteria(query) {
|
|
|
3146
3151
|
* @api public
|
|
3147
3152
|
*/
|
|
3148
3153
|
|
|
3149
|
-
Query.prototype.findOneAndUpdate = function(
|
|
3150
|
-
if (typeof
|
|
3154
|
+
Query.prototype.findOneAndUpdate = function(filter, doc, options) {
|
|
3155
|
+
if (typeof filter === 'function' ||
|
|
3151
3156
|
typeof doc === 'function' ||
|
|
3152
3157
|
typeof options === 'function' ||
|
|
3153
3158
|
typeof arguments[3] === 'function') {
|
|
@@ -3163,13 +3168,17 @@ Query.prototype.findOneAndUpdate = function(criteria, doc, options) {
|
|
|
3163
3168
|
options = undefined;
|
|
3164
3169
|
break;
|
|
3165
3170
|
case 1:
|
|
3166
|
-
doc =
|
|
3167
|
-
|
|
3171
|
+
doc = filter;
|
|
3172
|
+
filter = options = undefined;
|
|
3168
3173
|
break;
|
|
3169
3174
|
}
|
|
3170
3175
|
|
|
3171
|
-
if (mquery.canMerge(
|
|
3172
|
-
this.merge(
|
|
3176
|
+
if (mquery.canMerge(filter)) {
|
|
3177
|
+
this.merge(filter);
|
|
3178
|
+
} else if (filter != null) {
|
|
3179
|
+
this.error(
|
|
3180
|
+
new ObjectParameterError(filter, 'filter', 'findOneAndUpdate')
|
|
3181
|
+
);
|
|
3173
3182
|
}
|
|
3174
3183
|
|
|
3175
3184
|
// apply doc
|
|
@@ -3371,7 +3380,7 @@ Query.prototype.findOneAndRemove = function(conditions, options) {
|
|
|
3371
3380
|
*
|
|
3372
3381
|
* @method findOneAndDelete
|
|
3373
3382
|
* @memberOf Query
|
|
3374
|
-
* @param {Object} [
|
|
3383
|
+
* @param {Object} [filter]
|
|
3375
3384
|
* @param {Object} [options]
|
|
3376
3385
|
* @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
|
|
3377
3386
|
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
|
|
@@ -3381,8 +3390,8 @@ Query.prototype.findOneAndRemove = function(conditions, options) {
|
|
|
3381
3390
|
* @api public
|
|
3382
3391
|
*/
|
|
3383
3392
|
|
|
3384
|
-
Query.prototype.findOneAndDelete = function(
|
|
3385
|
-
if (typeof
|
|
3393
|
+
Query.prototype.findOneAndDelete = function(filter, options) {
|
|
3394
|
+
if (typeof filter === 'function' ||
|
|
3386
3395
|
typeof options === 'function' ||
|
|
3387
3396
|
typeof arguments[2] === 'function') {
|
|
3388
3397
|
throw new MongooseError('Query.prototype.findOneAndDelete() no longer accepts a callback');
|
|
@@ -3392,8 +3401,8 @@ Query.prototype.findOneAndDelete = function(conditions, options) {
|
|
|
3392
3401
|
this._validateOp();
|
|
3393
3402
|
this._validate();
|
|
3394
3403
|
|
|
3395
|
-
if (mquery.canMerge(
|
|
3396
|
-
this.merge(
|
|
3404
|
+
if (mquery.canMerge(filter)) {
|
|
3405
|
+
this.merge(filter);
|
|
3397
3406
|
}
|
|
3398
3407
|
|
|
3399
3408
|
options && this.setOptions(options);
|
|
@@ -3505,6 +3514,10 @@ Query.prototype.findOneAndReplace = function(filter, replacement, options) {
|
|
|
3505
3514
|
|
|
3506
3515
|
if (mquery.canMerge(filter)) {
|
|
3507
3516
|
this.merge(filter);
|
|
3517
|
+
} else if (filter != null) {
|
|
3518
|
+
this.error(
|
|
3519
|
+
new ObjectParameterError(filter, 'filter', 'findOneAndReplace')
|
|
3520
|
+
);
|
|
3508
3521
|
}
|
|
3509
3522
|
|
|
3510
3523
|
if (replacement != null) {
|
|
@@ -3548,16 +3561,6 @@ Query.prototype._findOneAndReplace = async function _findOneAndReplace() {
|
|
|
3548
3561
|
const filter = this._conditions;
|
|
3549
3562
|
const options = this._optionsForExec();
|
|
3550
3563
|
convertNewToReturnDocument(options);
|
|
3551
|
-
let fields = null;
|
|
3552
|
-
|
|
3553
|
-
this._applyPaths();
|
|
3554
|
-
if (this._fields != null) {
|
|
3555
|
-
options.projection = this._castFields(clone(this._fields));
|
|
3556
|
-
fields = options.projection;
|
|
3557
|
-
if (fields instanceof Error) {
|
|
3558
|
-
throw fields;
|
|
3559
|
-
}
|
|
3560
|
-
}
|
|
3561
3564
|
|
|
3562
3565
|
const runValidators = _getOption(this, 'runValidators', false);
|
|
3563
3566
|
if (runValidators === false) {
|
|
@@ -3786,7 +3789,7 @@ async function _updateThunk(op) {
|
|
|
3786
3789
|
const options = this._optionsForExec(this.model);
|
|
3787
3790
|
|
|
3788
3791
|
this._update = clone(this._update, options);
|
|
3789
|
-
const isOverwriting = this.
|
|
3792
|
+
const isOverwriting = this._mongooseOptions.overwrite && !hasDollarKeys(this._update);
|
|
3790
3793
|
if (isOverwriting) {
|
|
3791
3794
|
if (op === 'updateOne' || op === 'updateMany') {
|
|
3792
3795
|
throw new MongooseError('The MongoDB server disallows ' +
|
|
@@ -3795,7 +3798,7 @@ async function _updateThunk(op) {
|
|
|
3795
3798
|
}
|
|
3796
3799
|
this._update = new this.model(this._update, null, true);
|
|
3797
3800
|
} else {
|
|
3798
|
-
this._update = this._castUpdate(this._update,
|
|
3801
|
+
this._update = this._castUpdate(this._update, this._mongooseOptions.overwrite);
|
|
3799
3802
|
|
|
3800
3803
|
if (this._update == null || Object.keys(this._update).length === 0) {
|
|
3801
3804
|
return { acknowledged: false };
|
|
@@ -4883,6 +4886,9 @@ Query.prototype._castFields = function _castFields(fields) {
|
|
|
4883
4886
|
*/
|
|
4884
4887
|
|
|
4885
4888
|
Query.prototype._applyPaths = function applyPaths() {
|
|
4889
|
+
if (!this.model) {
|
|
4890
|
+
return;
|
|
4891
|
+
}
|
|
4886
4892
|
this._fields = this._fields || {};
|
|
4887
4893
|
helpers.applyPaths(this._fields, this.model.schema);
|
|
4888
4894
|
|
|
@@ -4941,9 +4947,6 @@ Query.prototype._applyPaths = function applyPaths() {
|
|
|
4941
4947
|
*/
|
|
4942
4948
|
|
|
4943
4949
|
Query.prototype.cursor = function cursor(opts) {
|
|
4944
|
-
this._applyPaths();
|
|
4945
|
-
this._fields = this._castFields(this._fields);
|
|
4946
|
-
|
|
4947
4950
|
if (opts) {
|
|
4948
4951
|
this.setOptions(opts);
|
|
4949
4952
|
}
|