mongoose 6.2.9 → 6.3.0
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 +28 -0
- package/dist/browser.umd.js +2 -1693
- package/lib/aggregate.js +59 -67
- package/lib/browser.js +4 -4
- package/lib/connection.js +21 -21
- package/lib/cursor/AggregationCursor.js +2 -2
- package/lib/cursor/ChangeStream.js +42 -2
- package/lib/cursor/QueryCursor.js +5 -3
- package/lib/document.js +39 -46
- package/lib/error/eachAsyncMultiError.js +41 -0
- package/lib/error/index.js +2 -2
- package/lib/helpers/cursor/eachAsync.js +44 -12
- package/lib/helpers/indexes/applySchemaCollation.js +13 -0
- package/lib/helpers/indexes/isTextIndex.js +16 -0
- package/lib/helpers/model/discriminator.js +1 -3
- package/lib/helpers/populate/markArraySubdocsPopulated.js +1 -1
- package/lib/helpers/projection/hasIncludedChildren.js +1 -1
- package/lib/helpers/query/applyGlobalOption.js +29 -0
- package/lib/helpers/query/castUpdate.js +3 -1
- package/lib/helpers/update/applyTimestampsToChildren.js +2 -2
- package/lib/helpers/update/applyTimestampsToUpdate.js +0 -1
- package/lib/index.js +33 -26
- package/lib/model.js +88 -90
- package/lib/options/SchemaArrayOptions.js +2 -2
- package/lib/options/SchemaBufferOptions.js +1 -1
- package/lib/options/SchemaDateOptions.js +2 -2
- package/lib/options/SchemaDocumentArrayOptions.js +3 -3
- package/lib/options/SchemaMapOptions.js +2 -2
- package/lib/options/SchemaNumberOptions.js +3 -3
- package/lib/options/SchemaObjectIdOptions.js +2 -2
- package/lib/options/SchemaStringOptions.js +1 -1
- package/lib/options/SchemaSubdocumentOptions.js +2 -2
- package/lib/options/SchemaTypeOptions.js +3 -3
- package/lib/query.js +273 -249
- package/lib/schema/SubdocumentPath.js +4 -3
- package/lib/schema/array.js +2 -2
- package/lib/schema/boolean.js +4 -4
- package/lib/schema/buffer.js +3 -3
- package/lib/schema/date.js +7 -7
- package/lib/schema/decimal128.js +2 -2
- package/lib/schema/documentarray.js +3 -3
- package/lib/schema/mixed.js +2 -2
- package/lib/schema/number.js +6 -6
- package/lib/schema/objectid.js +4 -7
- package/lib/schema/string.js +38 -16
- package/lib/schema.js +144 -30
- package/lib/schematype.js +75 -68
- package/lib/types/ArraySubdocument.js +1 -1
- package/lib/types/DocumentArray/methods/index.js +2 -2
- package/lib/types/array/index.js +1 -1
- package/lib/types/array/methods/index.js +13 -13
- package/lib/types/buffer.js +1 -1
- package/lib/types/decimal128.js +1 -1
- package/lib/types/objectid.js +1 -1
- package/lib/types/subdocument.js +31 -2
- package/lib/validoptions.js +1 -0
- package/lib/virtualtype.js +3 -3
- package/package.json +19 -13
- package/tools/repl.js +2 -1
- package/types/aggregate.d.ts +223 -0
- package/types/cursor.d.ts +10 -4
- package/types/index.d.ts +194 -209
- package/types/mongooseoptions.d.ts +10 -4
- package/lib/helpers/query/applyGlobalMaxTimeMS.js +0 -15
|
@@ -16,6 +16,7 @@ class ChangeStream extends EventEmitter {
|
|
|
16
16
|
|
|
17
17
|
this.driverChangeStream = null;
|
|
18
18
|
this.closed = false;
|
|
19
|
+
this.bindedEvents = false;
|
|
19
20
|
this.pipeline = pipeline;
|
|
20
21
|
this.options = options;
|
|
21
22
|
|
|
@@ -27,21 +28,60 @@ class ChangeStream extends EventEmitter {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
this.driverChangeStream = driverChangeStream;
|
|
30
|
-
this._bindEvents();
|
|
31
31
|
this.emit('ready');
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
_bindEvents() {
|
|
36
|
+
if (this.bindedEvents) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.bindedEvents = true;
|
|
41
|
+
|
|
42
|
+
if (this.driverChangeStream == null) {
|
|
43
|
+
this.once('ready', () => {
|
|
44
|
+
this.driverChangeStream.on('close', () => {
|
|
45
|
+
this.closed = true;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
['close', 'change', 'end', 'error'].forEach(ev => {
|
|
49
|
+
this.driverChangeStream.on(ev, data => this.emit(ev, data));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
36
56
|
this.driverChangeStream.on('close', () => {
|
|
37
57
|
this.closed = true;
|
|
38
58
|
});
|
|
39
59
|
|
|
40
60
|
['close', 'change', 'end', 'error'].forEach(ev => {
|
|
41
|
-
this.driverChangeStream.on(ev, data =>
|
|
61
|
+
this.driverChangeStream.on(ev, data => {
|
|
62
|
+
this.emit(ev, data);
|
|
63
|
+
});
|
|
42
64
|
});
|
|
43
65
|
}
|
|
44
66
|
|
|
67
|
+
hasNext(cb) {
|
|
68
|
+
return this.driverChangeStream.hasNext(cb);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
next(cb) {
|
|
72
|
+
return this.driverChangeStream.next(cb);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
on(event, handler) {
|
|
76
|
+
this._bindEvents();
|
|
77
|
+
return super.on(event, handler);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
once(event, handler) {
|
|
81
|
+
this._bindEvents();
|
|
82
|
+
return super.once(event, handler);
|
|
83
|
+
}
|
|
84
|
+
|
|
45
85
|
_queue(cb) {
|
|
46
86
|
this.once('ready', () => cb());
|
|
47
87
|
}
|
|
@@ -112,7 +112,7 @@ QueryCursor.prototype._read = function() {
|
|
|
112
112
|
* Registers a transform function which subsequently maps documents retrieved
|
|
113
113
|
* via the streams interface or `.next()`
|
|
114
114
|
*
|
|
115
|
-
* ####Example
|
|
115
|
+
* #### Example
|
|
116
116
|
*
|
|
117
117
|
* // Map documents returned by `data` events
|
|
118
118
|
* Thing.
|
|
@@ -211,7 +211,7 @@ QueryCursor.prototype.next = function(callback) {
|
|
|
211
211
|
* will wait for the promise to resolve before iterating on to the next one.
|
|
212
212
|
* Returns a promise that resolves when done.
|
|
213
213
|
*
|
|
214
|
-
* ####Example
|
|
214
|
+
* #### Example
|
|
215
215
|
*
|
|
216
216
|
* // Iterate over documents asynchronously
|
|
217
217
|
* Thing.
|
|
@@ -225,6 +225,8 @@ QueryCursor.prototype.next = function(callback) {
|
|
|
225
225
|
* @param {Function} fn
|
|
226
226
|
* @param {Object} [options]
|
|
227
227
|
* @param {Number} [options.parallel] the number of promises to execute in parallel. Defaults to 1.
|
|
228
|
+
* @param {Number} [options.batchSize] if set, will call `fn()` with arrays of documents with length at most `batchSize`
|
|
229
|
+
* @param {Boolean} [options.continueOnError=false] if true, `eachAsync()` iterates through all docs even if `fn` throws an error. If false, `eachAsync()` throws an error immediately if the given function `fn()` throws an error.
|
|
228
230
|
* @param {Function} [callback] executed when all docs have been processed
|
|
229
231
|
* @return {Promise}
|
|
230
232
|
* @api public
|
|
@@ -298,7 +300,7 @@ QueryCursor.prototype._transformForAsyncIterator = function() {
|
|
|
298
300
|
* You do not need to call this function explicitly, the JavaScript runtime
|
|
299
301
|
* will call it for you.
|
|
300
302
|
*
|
|
301
|
-
* ####Example
|
|
303
|
+
* #### Example
|
|
302
304
|
*
|
|
303
305
|
* // Works without using `cursor()`
|
|
304
306
|
* for await (const doc of Model.find([{ $sort: { name: 1 } }])) {
|
package/lib/document.js
CHANGED
|
@@ -94,7 +94,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
94
94
|
this.$__ = new InternalCache();
|
|
95
95
|
this.$isNew = 'isNew' in options ? options.isNew : true;
|
|
96
96
|
|
|
97
|
-
if (
|
|
97
|
+
if (options.priorDoc != null) {
|
|
98
98
|
this.$__.priorDoc = options.priorDoc;
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -119,7 +119,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
119
119
|
fields = undefined;
|
|
120
120
|
} else {
|
|
121
121
|
this.$__.strictMode = schema.options.strict;
|
|
122
|
-
if (fields
|
|
122
|
+
if (fields != null) {
|
|
123
123
|
this.$__.selected = fields;
|
|
124
124
|
}
|
|
125
125
|
}
|
|
@@ -177,8 +177,6 @@ function Document(obj, fields, skipId, options) {
|
|
|
177
177
|
$__applyDefaults(this, fields, exclude, hasIncludedChildren, false, options.skipDefaults);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
this.$__._id = this._id;
|
|
181
|
-
|
|
182
180
|
if (!this.$__.strictMode && obj) {
|
|
183
181
|
const _this = this;
|
|
184
182
|
const keys = Object.keys(this._doc);
|
|
@@ -268,7 +266,7 @@ Document.prototype.schema;
|
|
|
268
266
|
* is handy for passing data to middleware without conflicting with Mongoose
|
|
269
267
|
* internals.
|
|
270
268
|
*
|
|
271
|
-
* ####Example:
|
|
269
|
+
* #### Example:
|
|
272
270
|
*
|
|
273
271
|
* schema.pre('save', function() {
|
|
274
272
|
* // Mongoose will set `isNew` to `false` if `save()` succeeds
|
|
@@ -326,7 +324,7 @@ Document.prototype.isNew;
|
|
|
326
324
|
/**
|
|
327
325
|
* Set this property to add additional query filters when Mongoose saves this document and `isNew` is false.
|
|
328
326
|
*
|
|
329
|
-
* ####Example:
|
|
327
|
+
* #### Example:
|
|
330
328
|
*
|
|
331
329
|
* // Make sure `save()` never updates a soft deleted document.
|
|
332
330
|
* schema.pre('save', function() {
|
|
@@ -348,7 +346,7 @@ Object.defineProperty(Document.prototype, '$where', {
|
|
|
348
346
|
/**
|
|
349
347
|
* The string version of this documents _id.
|
|
350
348
|
*
|
|
351
|
-
* ####Note:
|
|
349
|
+
* #### Note:
|
|
352
350
|
*
|
|
353
351
|
* This getter exists on all documents by default. The getter can be disabled by setting the `id` [option](/docs/guide.html#id) of its `Schema` to false at construction time.
|
|
354
352
|
*
|
|
@@ -389,7 +387,7 @@ Document.prototype.errors;
|
|
|
389
387
|
* A string containing the current operation that Mongoose is executing
|
|
390
388
|
* on this document. May be `null`, `'save'`, `'validate'`, or `'remove'`.
|
|
391
389
|
*
|
|
392
|
-
* ####Example:
|
|
390
|
+
* #### Example:
|
|
393
391
|
*
|
|
394
392
|
* const doc = new Model({ name: 'test' });
|
|
395
393
|
* doc.$op; // null
|
|
@@ -743,8 +741,6 @@ Document.prototype.$__init = function(doc, opts) {
|
|
|
743
741
|
this.$emit('init', this);
|
|
744
742
|
this.constructor.emit('init', this);
|
|
745
743
|
|
|
746
|
-
this.$__._id = this._id;
|
|
747
|
-
|
|
748
744
|
const hasIncludedChildren = this.$__.exclude === false && this.$__.fields ?
|
|
749
745
|
$__hasIncludedChildren(this.$__.fields) :
|
|
750
746
|
null;
|
|
@@ -841,11 +837,11 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
841
837
|
/**
|
|
842
838
|
* Sends an update command with this document `_id` as the query selector.
|
|
843
839
|
*
|
|
844
|
-
* ####Example:
|
|
840
|
+
* #### Example:
|
|
845
841
|
*
|
|
846
842
|
* weirdCar.update({$inc: {wheels:1}}, { w: 1 }, callback);
|
|
847
843
|
*
|
|
848
|
-
* ####Valid options:
|
|
844
|
+
* #### Valid options:
|
|
849
845
|
*
|
|
850
846
|
* - same as in [Model.update](#model_Model.update)
|
|
851
847
|
*
|
|
@@ -876,11 +872,11 @@ Document.prototype.update = function update() {
|
|
|
876
872
|
/**
|
|
877
873
|
* Sends an updateOne command with this document `_id` as the query selector.
|
|
878
874
|
*
|
|
879
|
-
* ####Example:
|
|
875
|
+
* #### Example:
|
|
880
876
|
*
|
|
881
877
|
* weirdCar.updateOne({$inc: {wheels:1}}, { w: 1 }, callback);
|
|
882
878
|
*
|
|
883
|
-
* ####Valid options:
|
|
879
|
+
* #### Valid options:
|
|
884
880
|
*
|
|
885
881
|
* - same as in [Model.updateOne](#model_Model.updateOne)
|
|
886
882
|
*
|
|
@@ -922,7 +918,7 @@ Document.prototype.updateOne = function updateOne(doc, options, callback) {
|
|
|
922
918
|
/**
|
|
923
919
|
* Sends a replaceOne command with this document `_id` as the query selector.
|
|
924
920
|
*
|
|
925
|
-
* ####Valid options:
|
|
921
|
+
* #### Valid options:
|
|
926
922
|
*
|
|
927
923
|
* - same as in [Model.replaceOne](https://mongoosejs.com/docs/api/model.html#model_Model.replaceOne)
|
|
928
924
|
*
|
|
@@ -947,7 +943,7 @@ Document.prototype.replaceOne = function replaceOne() {
|
|
|
947
943
|
* automatically set `session` if you `save()` a doc that you got from a
|
|
948
944
|
* query with an associated session.
|
|
949
945
|
*
|
|
950
|
-
* ####Example:
|
|
946
|
+
* #### Example:
|
|
951
947
|
*
|
|
952
948
|
* const session = MyModel.startSession();
|
|
953
949
|
* const doc = await MyModel.findOne().session(session);
|
|
@@ -1514,7 +1510,7 @@ function _isManuallyPopulatedArray(val, ref) {
|
|
|
1514
1510
|
/**
|
|
1515
1511
|
* Sets the value of a path, or many paths.
|
|
1516
1512
|
*
|
|
1517
|
-
* ####Example:
|
|
1513
|
+
* #### Example:
|
|
1518
1514
|
*
|
|
1519
1515
|
* // path, value
|
|
1520
1516
|
* doc.set(path, value)
|
|
@@ -1718,7 +1714,7 @@ Document.prototype.$__setValue = function(path, val) {
|
|
|
1718
1714
|
/**
|
|
1719
1715
|
* Returns the value of a path.
|
|
1720
1716
|
*
|
|
1721
|
-
* ####Example
|
|
1717
|
+
* #### Example
|
|
1722
1718
|
*
|
|
1723
1719
|
* // path
|
|
1724
1720
|
* doc.get('age') // 47
|
|
@@ -1824,7 +1820,7 @@ Document.prototype.$__path = function(path) {
|
|
|
1824
1820
|
*
|
|
1825
1821
|
* _Very helpful when using [Mixed](https://mongoosejs.com/docs/schematypes.html#mixed) types._
|
|
1826
1822
|
*
|
|
1827
|
-
* ####Example:
|
|
1823
|
+
* #### Example:
|
|
1828
1824
|
*
|
|
1829
1825
|
* doc.mixed.type = 'changed';
|
|
1830
1826
|
* doc.markModified('mixed.type');
|
|
@@ -1847,7 +1843,7 @@ Document.prototype.markModified = function(path, scope) {
|
|
|
1847
1843
|
/**
|
|
1848
1844
|
* Clears the modified state on the specified path.
|
|
1849
1845
|
*
|
|
1850
|
-
* ####Example:
|
|
1846
|
+
* #### Example:
|
|
1851
1847
|
*
|
|
1852
1848
|
* doc.foo = 'bar';
|
|
1853
1849
|
* doc.unmarkModified('foo');
|
|
@@ -1867,7 +1863,7 @@ Document.prototype.unmarkModified = function(path) {
|
|
|
1867
1863
|
/**
|
|
1868
1864
|
* Don't run validation on this path or persist changes to this path.
|
|
1869
1865
|
*
|
|
1870
|
-
* ####Example:
|
|
1866
|
+
* #### Example:
|
|
1871
1867
|
*
|
|
1872
1868
|
* doc.foo = null;
|
|
1873
1869
|
* doc.$ignore('foo');
|
|
@@ -1892,7 +1888,7 @@ Document.prototype.$ignore = function(path) {
|
|
|
1892
1888
|
* A path `a` may be in `modifiedPaths()` but not in `directModifiedPaths()`
|
|
1893
1889
|
* because a child of `a` was directly modified.
|
|
1894
1890
|
*
|
|
1895
|
-
* ####Example
|
|
1891
|
+
* #### Example
|
|
1896
1892
|
* const schema = new Schema({ foo: String, nested: { bar: String } });
|
|
1897
1893
|
* const Model = mongoose.model('Test', schema);
|
|
1898
1894
|
* await Model.create({ foo: 'original', nested: { bar: 'original' } });
|
|
@@ -1915,7 +1911,7 @@ Document.prototype.directModifiedPaths = function() {
|
|
|
1915
1911
|
* Useful for determining whether this subdoc will get stripped out by the
|
|
1916
1912
|
* [minimize option](/docs/guide.html#minimize).
|
|
1917
1913
|
*
|
|
1918
|
-
* ####Example:
|
|
1914
|
+
* #### Example:
|
|
1919
1915
|
* const schema = new Schema({ nested: { foo: String } });
|
|
1920
1916
|
* const Model = mongoose.model('Test', schema);
|
|
1921
1917
|
* const doc = new Model({});
|
|
@@ -2048,7 +2044,7 @@ Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
|
|
|
2048
2044
|
*
|
|
2049
2045
|
* If `path` is given, checks if a path or any full path containing `path` as part of its path chain has been modified.
|
|
2050
2046
|
*
|
|
2051
|
-
* ####Example
|
|
2047
|
+
* #### Example
|
|
2052
2048
|
*
|
|
2053
2049
|
* doc.set('documents.0.title', 'changed');
|
|
2054
2050
|
* doc.isModified() // true
|
|
@@ -2094,7 +2090,7 @@ Document.prototype[documentIsModified] = Document.prototype.isModified;
|
|
|
2094
2090
|
/**
|
|
2095
2091
|
* Checks if a path is set to its default.
|
|
2096
2092
|
*
|
|
2097
|
-
* ####Example
|
|
2093
|
+
* #### Example
|
|
2098
2094
|
*
|
|
2099
2095
|
* MyModel = mongoose.model('test', { name: { type: String, default: 'Val '} });
|
|
2100
2096
|
* const m = new MyModel();
|
|
@@ -2128,7 +2124,7 @@ Document.prototype.$isDefault = function(path) {
|
|
|
2128
2124
|
/**
|
|
2129
2125
|
* Getter/setter, determines whether the document was removed or not.
|
|
2130
2126
|
*
|
|
2131
|
-
* ####Example:
|
|
2127
|
+
* #### Example:
|
|
2132
2128
|
* const product = await product.remove();
|
|
2133
2129
|
* product.$isDeleted(); // true
|
|
2134
2130
|
* product.remove(); // no-op, doesn't send anything to the db
|
|
@@ -2158,7 +2154,7 @@ Document.prototype.$isDeleted = function(val) {
|
|
|
2158
2154
|
/**
|
|
2159
2155
|
* Returns true if `path` was directly set and modified, else false.
|
|
2160
2156
|
*
|
|
2161
|
-
* ####Example
|
|
2157
|
+
* #### Example
|
|
2162
2158
|
*
|
|
2163
2159
|
* doc.set('documents.0.title', 'changed');
|
|
2164
2160
|
* doc.isDirectModified('documents.0.title') // true
|
|
@@ -2214,7 +2210,7 @@ Document.prototype.isInit = function(path) {
|
|
|
2214
2210
|
/**
|
|
2215
2211
|
* Checks if `path` was selected in the source query which initialized this document.
|
|
2216
2212
|
*
|
|
2217
|
-
* ####Example
|
|
2213
|
+
* #### Example
|
|
2218
2214
|
*
|
|
2219
2215
|
* const doc = await Thing.findOne().select('name');
|
|
2220
2216
|
* doc.isSelected('name') // true
|
|
@@ -2295,7 +2291,7 @@ Document.prototype.$__isSelected = Document.prototype.isSelected;
|
|
|
2295
2291
|
* Checks if `path` was explicitly selected. If no projection, always returns
|
|
2296
2292
|
* true.
|
|
2297
2293
|
*
|
|
2298
|
-
* ####Example
|
|
2294
|
+
* #### Example
|
|
2299
2295
|
*
|
|
2300
2296
|
* Thing.findOne().select('nested.name').exec(function (err, doc) {
|
|
2301
2297
|
* doc.isDirectSelected('nested.name') // true
|
|
@@ -2357,11 +2353,11 @@ Document.prototype.isDirectSelected = function isDirectSelected(path) {
|
|
|
2357
2353
|
/**
|
|
2358
2354
|
* Executes registered validation rules for this document.
|
|
2359
2355
|
*
|
|
2360
|
-
* ####Note:
|
|
2356
|
+
* #### Note:
|
|
2361
2357
|
*
|
|
2362
2358
|
* This method is called `pre` save and if a validation rule is violated, [save](#model_Model-save) is aborted and the error is returned to your `callback`.
|
|
2363
2359
|
*
|
|
2364
|
-
* ####Example:
|
|
2360
|
+
* #### Example:
|
|
2365
2361
|
*
|
|
2366
2362
|
* doc.validate(function (err) {
|
|
2367
2363
|
* if (err) handleError(err);
|
|
@@ -2485,10 +2481,7 @@ function _getPathsToValidate(doc) {
|
|
|
2485
2481
|
if (subdoc.$basePath) {
|
|
2486
2482
|
// Remove child paths for now, because we'll be validating the whole
|
|
2487
2483
|
// subdoc
|
|
2488
|
-
|
|
2489
|
-
subdoc.ownerDocument();
|
|
2490
|
-
}
|
|
2491
|
-
const fullPathToSubdoc = subdoc.$__.fullPath;
|
|
2484
|
+
const fullPathToSubdoc = subdoc.$__fullPathWithIndexes();
|
|
2492
2485
|
|
|
2493
2486
|
for (const p of paths) {
|
|
2494
2487
|
if (p === null || p.startsWith(fullPathToSubdoc + '.')) {
|
|
@@ -2826,11 +2819,11 @@ function _handlePathsToSkip(paths, pathsToSkip) {
|
|
|
2826
2819
|
/**
|
|
2827
2820
|
* Executes registered validation rules (skipping asynchronous validators) for this document.
|
|
2828
2821
|
*
|
|
2829
|
-
* ####Note:
|
|
2822
|
+
* #### Note:
|
|
2830
2823
|
*
|
|
2831
2824
|
* This method is useful if you need synchronous validation.
|
|
2832
2825
|
*
|
|
2833
|
-
* ####Example:
|
|
2826
|
+
* #### Example:
|
|
2834
2827
|
*
|
|
2835
2828
|
* const err = doc.validateSync();
|
|
2836
2829
|
* if (err) {
|
|
@@ -3065,7 +3058,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3065
3058
|
* Saves this document by inserting a new document into the database if [document.isNew](/docs/api.html#document_Document-isNew) is `true`,
|
|
3066
3059
|
* or sends an [updateOne](/docs/api.html#document_Document-updateOne) operation **only** with the modifications to the database, it does not replace the whole document in the latter case.
|
|
3067
3060
|
*
|
|
3068
|
-
* ####Example:
|
|
3061
|
+
* #### Example:
|
|
3069
3062
|
*
|
|
3070
3063
|
* product.sold = Date.now();
|
|
3071
3064
|
* product = await product.save();
|
|
@@ -3073,7 +3066,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3073
3066
|
* If save is successful, the returned promise will fulfill with the document
|
|
3074
3067
|
* saved.
|
|
3075
3068
|
*
|
|
3076
|
-
* ####Example:
|
|
3069
|
+
* #### Example:
|
|
3077
3070
|
*
|
|
3078
3071
|
* const newProduct = await product.save();
|
|
3079
3072
|
* newProduct === product; // true
|
|
@@ -3601,7 +3594,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3601
3594
|
*
|
|
3602
3595
|
* Buffers are converted to instances of [mongodb.Binary](https://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html) for proper storage.
|
|
3603
3596
|
*
|
|
3604
|
-
* ####Options:
|
|
3597
|
+
* #### Options:
|
|
3605
3598
|
*
|
|
3606
3599
|
* - `getters` apply all getters (path and virtual getters), defaults to false
|
|
3607
3600
|
* - `aliases` apply all aliases if `virtuals=true`, defaults to true
|
|
@@ -3613,7 +3606,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3613
3606
|
* - `flattenMaps` convert Maps to POJOs. Useful if you want to JSON.stringify() the result of toObject(), defaults to false
|
|
3614
3607
|
* - `useProjection` set to `true` to omit fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema.
|
|
3615
3608
|
*
|
|
3616
|
-
* ####Getters/Virtuals
|
|
3609
|
+
* #### Getters/Virtuals
|
|
3617
3610
|
*
|
|
3618
3611
|
* Example of only applying path getters
|
|
3619
3612
|
*
|
|
@@ -3631,7 +3624,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3631
3624
|
*
|
|
3632
3625
|
* schema.set('toObject', { virtuals: true })
|
|
3633
3626
|
*
|
|
3634
|
-
* ####Transform
|
|
3627
|
+
* #### Transform
|
|
3635
3628
|
*
|
|
3636
3629
|
* We may need to perform a transformation of the resulting object based on some criteria, say to remove some sensitive information or return a custom object. In this case we set the optional `transform` function.
|
|
3637
3630
|
*
|
|
@@ -3643,7 +3636,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3643
3636
|
* - `ret` The plain object representation which has been converted
|
|
3644
3637
|
* - `options` The options in use (either schema options or the options passed inline)
|
|
3645
3638
|
*
|
|
3646
|
-
* ####Example
|
|
3639
|
+
* #### Example
|
|
3647
3640
|
*
|
|
3648
3641
|
* // specify the transform schema option
|
|
3649
3642
|
* if (!schema.options.toObject) schema.options.toObject = {};
|
|
@@ -4137,7 +4130,7 @@ Document.prototype.equals = function(doc) {
|
|
|
4137
4130
|
/**
|
|
4138
4131
|
* Populates paths on an existing document.
|
|
4139
4132
|
*
|
|
4140
|
-
* ####Example:
|
|
4133
|
+
* #### Example:
|
|
4141
4134
|
*
|
|
4142
4135
|
* await doc.populate([
|
|
4143
4136
|
* 'stories',
|
|
@@ -4254,7 +4247,7 @@ Document.prototype.$getPopulatedDocs = function $getPopulatedDocs() {
|
|
|
4254
4247
|
/**
|
|
4255
4248
|
* Gets _id(s) used during population of the given `path`.
|
|
4256
4249
|
*
|
|
4257
|
-
* ####Example:
|
|
4250
|
+
* #### Example:
|
|
4258
4251
|
*
|
|
4259
4252
|
* Model.findOne().populate('author').exec(function (err, doc) {
|
|
4260
4253
|
* console.log(doc.author.name) // Dr.Seuss
|
|
@@ -4316,7 +4309,7 @@ Document.prototype.$populated = Document.prototype.populated;
|
|
|
4316
4309
|
/**
|
|
4317
4310
|
* Takes a populated field and returns it to its unpopulated state.
|
|
4318
4311
|
*
|
|
4319
|
-
* ####Example:
|
|
4312
|
+
* #### Example:
|
|
4320
4313
|
*
|
|
4321
4314
|
* Model.findOne().populate('author').exec(function (err, doc) {
|
|
4322
4315
|
* console.log(doc.author.name); // Dr.Seuss
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Module dependencies.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const MongooseError = require('./');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* If `eachAsync()` is called with `continueOnError: true`, there can be
|
|
12
|
+
* multiple errors. This error class contains an `errors` property, which
|
|
13
|
+
* contains an array of all errors that occurred in `eachAsync()`.
|
|
14
|
+
*
|
|
15
|
+
* @api private
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
class EachAsyncMultiError extends MongooseError {
|
|
19
|
+
/**
|
|
20
|
+
* @param {String} connectionString
|
|
21
|
+
*/
|
|
22
|
+
constructor(errors) {
|
|
23
|
+
let preview = errors.map(e => e.message).join(', ');
|
|
24
|
+
if (preview.length > 50) {
|
|
25
|
+
preview = preview.slice(0, 50) + '...';
|
|
26
|
+
}
|
|
27
|
+
super(`eachAsync() finished with ${errors.length} errors: ${preview}`);
|
|
28
|
+
|
|
29
|
+
this.errors = errors;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Object.defineProperty(EachAsyncMultiError.prototype, 'name', {
|
|
34
|
+
value: 'EachAsyncMultiError'
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/*!
|
|
38
|
+
* exports
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
module.exports = EachAsyncMultiError;
|
package/lib/error/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* MongooseError constructor. MongooseError is the base class for all
|
|
5
5
|
* Mongoose-specific errors.
|
|
6
6
|
*
|
|
7
|
-
* ####Example:
|
|
7
|
+
* #### Example:
|
|
8
8
|
* const Model = mongoose.model('Test', new Schema({ answer: Number }));
|
|
9
9
|
* const doc = new Model({ answer: 'not a number' });
|
|
10
10
|
* const err = doc.validateSync();
|
|
@@ -105,7 +105,7 @@ MongooseError.ValidationError = require('./validation');
|
|
|
105
105
|
* A `ValidationError` has a hash of `errors` that contain individual
|
|
106
106
|
* `ValidatorError` instances.
|
|
107
107
|
*
|
|
108
|
-
* ####Example:
|
|
108
|
+
* #### Example:
|
|
109
109
|
*
|
|
110
110
|
* const schema = Schema({ name: { type: String, required: true } });
|
|
111
111
|
* const Model = mongoose.model('Test', schema);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Module dependencies.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
const EachAsyncMultiError = require('../../error/eachAsyncMultiError');
|
|
7
8
|
const immediate = require('../immediate');
|
|
8
9
|
const promiseOrCallback = require('../promiseOrCallback');
|
|
9
10
|
|
|
@@ -24,10 +25,11 @@ const promiseOrCallback = require('../promiseOrCallback');
|
|
|
24
25
|
module.exports = function eachAsync(next, fn, options, callback) {
|
|
25
26
|
const parallel = options.parallel || 1;
|
|
26
27
|
const batchSize = options.batchSize;
|
|
28
|
+
const continueOnError = options.continueOnError;
|
|
29
|
+
const aggregatedErrors = [];
|
|
27
30
|
const enqueue = asyncQueue();
|
|
28
31
|
|
|
29
32
|
return promiseOrCallback(callback, cb => {
|
|
30
|
-
|
|
31
33
|
if (batchSize != null) {
|
|
32
34
|
if (typeof batchSize !== 'number') {
|
|
33
35
|
throw new TypeError('batchSize must be a number');
|
|
@@ -62,14 +64,22 @@ module.exports = function eachAsync(next, fn, options, callback) {
|
|
|
62
64
|
return done();
|
|
63
65
|
}
|
|
64
66
|
if (err != null) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
if (continueOnError) {
|
|
68
|
+
aggregatedErrors.push(err);
|
|
69
|
+
} else {
|
|
70
|
+
error = err;
|
|
71
|
+
finalCallback(err);
|
|
72
|
+
return done();
|
|
73
|
+
}
|
|
68
74
|
}
|
|
69
75
|
if (doc == null) {
|
|
70
76
|
drained = true;
|
|
71
77
|
if (handleResultsInProgress <= 0) {
|
|
72
|
-
|
|
78
|
+
const finalErr = continueOnError ?
|
|
79
|
+
createEachAsyncMultiError(aggregatedErrors) :
|
|
80
|
+
error;
|
|
81
|
+
|
|
82
|
+
finalCallback(finalErr);
|
|
73
83
|
} else if (batchSize && documentsBatch.length) {
|
|
74
84
|
handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack);
|
|
75
85
|
}
|
|
@@ -102,11 +112,18 @@ module.exports = function eachAsync(next, fn, options, callback) {
|
|
|
102
112
|
--handleResultsInProgress;
|
|
103
113
|
}
|
|
104
114
|
if (err != null) {
|
|
105
|
-
|
|
106
|
-
|
|
115
|
+
if (continueOnError) {
|
|
116
|
+
aggregatedErrors.push(err);
|
|
117
|
+
} else {
|
|
118
|
+
error = err;
|
|
119
|
+
return finalCallback(err);
|
|
120
|
+
}
|
|
107
121
|
}
|
|
108
122
|
if (drained && handleResultsInProgress <= 0) {
|
|
109
|
-
|
|
123
|
+
const finalErr = continueOnError ?
|
|
124
|
+
createEachAsyncMultiError(aggregatedErrors) :
|
|
125
|
+
error;
|
|
126
|
+
return finalCallback(finalErr);
|
|
110
127
|
}
|
|
111
128
|
|
|
112
129
|
immediate(() => enqueue(fetch));
|
|
@@ -118,11 +135,18 @@ module.exports = function eachAsync(next, fn, options, callback) {
|
|
|
118
135
|
}
|
|
119
136
|
|
|
120
137
|
function handleNextResult(doc, i, callback) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
138
|
+
let maybePromise;
|
|
139
|
+
try {
|
|
140
|
+
maybePromise = fn(doc, i);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
return callback(err);
|
|
143
|
+
}
|
|
144
|
+
if (maybePromise && typeof maybePromise.then === 'function') {
|
|
145
|
+
maybePromise.then(
|
|
124
146
|
function() { callback(null); },
|
|
125
|
-
function(error) {
|
|
147
|
+
function(error) {
|
|
148
|
+
callback(error || new Error('`eachAsync()` promise rejected without error'));
|
|
149
|
+
});
|
|
126
150
|
} else {
|
|
127
151
|
callback(null);
|
|
128
152
|
}
|
|
@@ -158,3 +182,11 @@ function asyncQueue() {
|
|
|
158
182
|
}
|
|
159
183
|
}
|
|
160
184
|
}
|
|
185
|
+
|
|
186
|
+
function createEachAsyncMultiError(aggregatedErrors) {
|
|
187
|
+
if (aggregatedErrors.length === 0) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return new EachAsyncMultiError(aggregatedErrors);
|
|
192
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const isTextIndex = require('./isTextIndex');
|
|
4
|
+
|
|
5
|
+
module.exports = function applySchemaCollation(indexKeys, indexOptions, schemaOptions) {
|
|
6
|
+
if (isTextIndex(indexKeys)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (schemaOptions.hasOwnProperty('collation') && !indexOptions.hasOwnProperty('collation')) {
|
|
11
|
+
indexOptions.collation = schemaOptions.collation;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns `true` if the given index options have a `text` option.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
module.exports = function isTextIndex(indexKeys) {
|
|
8
|
+
let isTextIndex = false;
|
|
9
|
+
for (const key of Object.keys(indexKeys)) {
|
|
10
|
+
if (indexKeys[key] === 'text') {
|
|
11
|
+
isTextIndex = true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return isTextIndex;
|
|
16
|
+
};
|
|
@@ -17,7 +17,6 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
|
|
20
|
-
|
|
21
20
|
if (!(schema && schema.instanceOfSchema)) {
|
|
22
21
|
throw new Error('You must pass a valid discriminator Schema');
|
|
23
22
|
}
|
|
@@ -109,7 +108,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
|
|
|
109
108
|
|
|
110
109
|
utils.merge(schema, baseSchema, {
|
|
111
110
|
isDiscriminatorSchemaMerge: true,
|
|
112
|
-
omit: { discriminators: true, base: true },
|
|
111
|
+
omit: { discriminators: true, base: true, _applyDiscriminators: true },
|
|
113
112
|
omitNested: conflictingPaths.reduce((cur, path) => {
|
|
114
113
|
cur['tree.' + path] = true;
|
|
115
114
|
return cur;
|
|
@@ -141,7 +140,6 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
|
|
|
141
140
|
obj[key][schema.options.typeKey] = existingPath ? existingPath.options[schema.options.typeKey] : String;
|
|
142
141
|
schema.add(obj);
|
|
143
142
|
|
|
144
|
-
|
|
145
143
|
schema.discriminatorMapping = { key: key, value: value, isRoot: false };
|
|
146
144
|
|
|
147
145
|
if (baseSchema.options.collection) {
|
|
@@ -6,7 +6,7 @@ const utils = require('../../utils');
|
|
|
6
6
|
* If populating a path within a document array, make sure each
|
|
7
7
|
* subdoc within the array knows its subpaths are populated.
|
|
8
8
|
*
|
|
9
|
-
* ####Example:
|
|
9
|
+
* #### Example:
|
|
10
10
|
* const doc = await Article.findOne().populate('comments.author');
|
|
11
11
|
* doc.comments[0].populated('author'); // Should be set
|
|
12
12
|
*/
|