mongoose 5.0.17 → 5.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/.travis.yml +4 -3
- package/History.md +61 -0
- package/lib/aggregate.js +15 -4
- package/lib/connection.js +12 -0
- package/lib/document.js +79 -18
- package/lib/drivers/browser/objectid.js +12 -0
- package/lib/drivers/node-mongodb-native/collection.js +46 -35
- package/lib/error/version.js +4 -2
- package/lib/index.js +12 -7
- package/lib/internal.js +1 -0
- package/lib/model.js +329 -96
- package/lib/plugins/idGetter.js +0 -12
- package/lib/plugins/saveSubdocs.js +1 -1
- package/lib/query.js +202 -109
- package/lib/queryhelpers.js +59 -32
- package/lib/schema/array.js +6 -3
- package/lib/schema/date.js +5 -2
- package/lib/schema/decimal128.js +4 -0
- package/lib/schema/embedded.js +15 -9
- package/lib/schema/index.js +2 -0
- package/lib/schema/map.js +29 -0
- package/lib/schema/objectid.js +0 -20
- package/lib/schema.js +49 -9
- package/lib/schematype.js +19 -1
- package/lib/services/model/applyHooks.js +22 -2
- package/lib/services/model/applyMethods.js +14 -4
- package/lib/services/populate/getVirtual.js +4 -0
- package/lib/services/query/castUpdate.js +1 -1
- package/lib/services/query/completeMany.js +47 -0
- package/lib/types/buffer.js +1 -1
- package/lib/types/documentarray.js +16 -2
- package/lib/types/embedded.js +33 -1
- package/lib/types/index.js +2 -0
- package/lib/types/map.js +149 -0
- package/lib/types/objectid.js +12 -0
- package/lib/types/subdocument.js +30 -1
- package/lib/utils.js +49 -6
- package/migrating_to_5.md +1 -1
- package/package.json +5 -5
package/lib/schema/date.js
CHANGED
|
@@ -232,9 +232,12 @@ SchemaDate.prototype.cast = function(value) {
|
|
|
232
232
|
|
|
233
233
|
if (value instanceof Number || typeof value === 'number') {
|
|
234
234
|
date = new Date(value);
|
|
235
|
+
} else if (typeof value === 'string' && !isNaN(Number(value)) && (Number(value) >= 275761 || Number(value) < -271820)) {
|
|
236
|
+
// string representation of milliseconds take this path
|
|
237
|
+
date = new Date(Number(value));
|
|
235
238
|
} else if (typeof value.valueOf === 'function') {
|
|
236
|
-
// support for moment.js. This is also the path strings will take because
|
|
237
|
-
// have a `valueOf()`
|
|
239
|
+
// support for moment.js. This is also the path strings will take because
|
|
240
|
+
// strings have a `valueOf()`
|
|
238
241
|
date = new Date(value.valueOf());
|
|
239
242
|
} else {
|
|
240
243
|
// fallback
|
package/lib/schema/decimal128.js
CHANGED
|
@@ -128,6 +128,10 @@ Decimal128.prototype.cast = function(value, doc, init) {
|
|
|
128
128
|
return Decimal128Type.fromString(String(value));
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
if (typeof value.valueOf === 'function' && typeof value.valueOf() === 'string') {
|
|
132
|
+
return Decimal128Type.fromString(value.valueOf());
|
|
133
|
+
}
|
|
134
|
+
|
|
131
135
|
throw new CastError('Decimal128', value, this.path);
|
|
132
136
|
};
|
|
133
137
|
|
package/lib/schema/embedded.js
CHANGED
|
@@ -219,7 +219,7 @@ Embedded.prototype.castForQuery = function($conditional, val) {
|
|
|
219
219
|
* @api private
|
|
220
220
|
*/
|
|
221
221
|
|
|
222
|
-
Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
222
|
+
Embedded.prototype.doValidate = function(value, fn, scope, options) {
|
|
223
223
|
var Constructor = this.caster;
|
|
224
224
|
var discriminatorKey = Constructor.schema.options.discriminatorKey;
|
|
225
225
|
if (value != null &&
|
|
@@ -235,6 +235,13 @@ Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
if (options && options.skipSchemaValidators) {
|
|
239
|
+
if (!(value instanceof Constructor)) {
|
|
240
|
+
value = new Constructor(value, null, scope);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return value.validate(fn);
|
|
244
|
+
}
|
|
238
245
|
|
|
239
246
|
SchemaType.prototype.doValidate.call(this, value, function(error) {
|
|
240
247
|
if (error) {
|
|
@@ -244,10 +251,7 @@ Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
|
244
251
|
return fn(null);
|
|
245
252
|
}
|
|
246
253
|
|
|
247
|
-
|
|
248
|
-
value = new Constructor(value);
|
|
249
|
-
}
|
|
250
|
-
value.validate({__noPromise: true}, fn);
|
|
254
|
+
value.validate(fn);
|
|
251
255
|
}, scope);
|
|
252
256
|
};
|
|
253
257
|
|
|
@@ -257,10 +261,12 @@ Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
|
257
261
|
* @api private
|
|
258
262
|
*/
|
|
259
263
|
|
|
260
|
-
Embedded.prototype.doValidateSync = function(value, scope) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
+
Embedded.prototype.doValidateSync = function(value, scope, options) {
|
|
265
|
+
if (!options || !options.skipSchemaValidators) {
|
|
266
|
+
var schemaTypeError = SchemaType.prototype.doValidateSync.call(this, value, scope);
|
|
267
|
+
if (schemaTypeError) {
|
|
268
|
+
return schemaTypeError;
|
|
269
|
+
}
|
|
264
270
|
}
|
|
265
271
|
if (!value) {
|
|
266
272
|
return;
|
package/lib/schema/index.js
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* ignore
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const MongooseMap = require('../types/map');
|
|
8
|
+
const SchemaType = require('../schematype');
|
|
9
|
+
|
|
10
|
+
/*!
|
|
11
|
+
* ignore
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
class SchemaMap extends SchemaType {
|
|
15
|
+
constructor(key, options) {
|
|
16
|
+
super(key, options, 'Map');
|
|
17
|
+
this.$isSchemaMap = true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
cast(val, doc) {
|
|
21
|
+
if (val instanceof MongooseMap) {
|
|
22
|
+
return val;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return new MongooseMap(val, this.path, doc, this.$__schemaType);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = SchemaMap;
|
package/lib/schema/objectid.js
CHANGED
|
@@ -178,26 +178,6 @@ ObjectId.prototype.$conditionalHandlers =
|
|
|
178
178
|
$lte: handleSingle
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
-
/**
|
|
182
|
-
* Casts contents for queries.
|
|
183
|
-
*
|
|
184
|
-
* @param {String} $conditional
|
|
185
|
-
* @param {any} [val]
|
|
186
|
-
* @api private
|
|
187
|
-
*/
|
|
188
|
-
|
|
189
|
-
ObjectId.prototype.castForQuery = function($conditional, val) {
|
|
190
|
-
var handler;
|
|
191
|
-
if (arguments.length === 2) {
|
|
192
|
-
handler = this.$conditionalHandlers[$conditional];
|
|
193
|
-
if (!handler) {
|
|
194
|
-
throw new Error('Can\'t use ' + $conditional + ' with ObjectId.');
|
|
195
|
-
}
|
|
196
|
-
return handler.call(this, val);
|
|
197
|
-
}
|
|
198
|
-
return this._castForQuery($conditional);
|
|
199
|
-
};
|
|
200
|
-
|
|
201
181
|
/*!
|
|
202
182
|
* ignore
|
|
203
183
|
*/
|
package/lib/schema.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
/*!
|
|
2
4
|
* Module dependencies.
|
|
3
5
|
*/
|
|
@@ -72,6 +74,7 @@ function Schema(obj, options) {
|
|
|
72
74
|
this.callQueue = [];
|
|
73
75
|
this._indexes = [];
|
|
74
76
|
this.methods = {};
|
|
77
|
+
this.methodOptions = {};
|
|
75
78
|
this.statics = {};
|
|
76
79
|
this.tree = {};
|
|
77
80
|
this.query = {};
|
|
@@ -239,6 +242,7 @@ Schema.prototype.clone = function() {
|
|
|
239
242
|
s.options = utils.clone(this.options);
|
|
240
243
|
s.callQueue = this.callQueue.map(function(f) { return f; });
|
|
241
244
|
s.methods = utils.clone(this.methods);
|
|
245
|
+
s.methodOptions = utils.clone(this.methodOptions);
|
|
242
246
|
s.statics = utils.clone(this.statics);
|
|
243
247
|
s.query = utils.clone(this.query);
|
|
244
248
|
s.plugins = Array.prototype.slice.call(this.plugins);
|
|
@@ -381,6 +385,7 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
381
385
|
*/
|
|
382
386
|
|
|
383
387
|
Schema.reserved = Object.create(null);
|
|
388
|
+
Schema.prototype.reserved = Schema.reserved;
|
|
384
389
|
var reserved = Schema.reserved;
|
|
385
390
|
// Core object
|
|
386
391
|
reserved['prototype'] =
|
|
@@ -443,6 +448,17 @@ Schema.prototype.path = function(path, obj) {
|
|
|
443
448
|
return this.singleNestedPaths[path];
|
|
444
449
|
}
|
|
445
450
|
|
|
451
|
+
// Look for maps
|
|
452
|
+
for (let _path of Object.keys(this.paths)) {
|
|
453
|
+
if (!_path.includes('.$*')) {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
const re = new RegExp('^' + _path.replace(/\.\$\*/g, '.[^.]+') + '$');
|
|
457
|
+
if (re.test(path)) {
|
|
458
|
+
return this.paths[_path];
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
446
462
|
// subpaths?
|
|
447
463
|
return /\.\d+\.?.*$/.test(path)
|
|
448
464
|
? getPositionalPath(this, path)
|
|
@@ -459,16 +475,16 @@ Schema.prototype.path = function(path, obj) {
|
|
|
459
475
|
}
|
|
460
476
|
|
|
461
477
|
// update the tree
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
478
|
+
const subpaths = path.split(/\./);
|
|
479
|
+
let last = subpaths.pop();
|
|
480
|
+
let branch = this.tree;
|
|
465
481
|
|
|
466
482
|
subpaths.forEach(function(sub, i) {
|
|
467
483
|
if (!branch[sub]) {
|
|
468
484
|
branch[sub] = {};
|
|
469
485
|
}
|
|
470
486
|
if (typeof branch[sub] !== 'object') {
|
|
471
|
-
|
|
487
|
+
const msg = 'Cannot set nested path `' + path + '`. '
|
|
472
488
|
+ 'Parent path `'
|
|
473
489
|
+ subpaths.slice(0, i).concat([sub]).join('.')
|
|
474
490
|
+ '` already set to type ' + branch[sub].name
|
|
@@ -478,17 +494,26 @@ Schema.prototype.path = function(path, obj) {
|
|
|
478
494
|
branch = branch[sub];
|
|
479
495
|
});
|
|
480
496
|
|
|
481
|
-
|
|
482
497
|
branch[last] = utils.clone(obj);
|
|
483
498
|
|
|
484
499
|
this.paths[path] = Schema.interpretAsType(path, obj, this.options);
|
|
485
500
|
|
|
501
|
+
if (this.paths[path].$isSchemaMap) {
|
|
502
|
+
// Maps can have arbitrary keys, so `$*` is internal shorthand for "any key"
|
|
503
|
+
// The '$' is to imply this path should never be stored in MongoDB so we
|
|
504
|
+
// can easily build a regexp out of this path, and '*' to imply "any key."
|
|
505
|
+
const mapPath = path + '.$*';
|
|
506
|
+
this.paths[path + '.$*'] = Schema.interpretAsType(mapPath,
|
|
507
|
+
obj.of || { type: {} }, this.options);
|
|
508
|
+
this.paths[path].$__schemaType = this.paths[path + '.$*'];
|
|
509
|
+
}
|
|
510
|
+
|
|
486
511
|
if (this.paths[path].$isSingleNested) {
|
|
487
|
-
for (
|
|
512
|
+
for (let key in this.paths[path].schema.paths) {
|
|
488
513
|
this.singleNestedPaths[path + '.' + key] =
|
|
489
514
|
this.paths[path].schema.paths[key];
|
|
490
515
|
}
|
|
491
|
-
for (key in this.paths[path].schema.singleNestedPaths) {
|
|
516
|
+
for (let key in this.paths[path].schema.singleNestedPaths) {
|
|
492
517
|
this.singleNestedPaths[path + '.' + key] =
|
|
493
518
|
this.paths[path].schema.singleNestedPaths[key];
|
|
494
519
|
}
|
|
@@ -722,6 +747,17 @@ Schema.prototype.pathType = function(path) {
|
|
|
722
747
|
return 'real';
|
|
723
748
|
}
|
|
724
749
|
|
|
750
|
+
// Look for maps
|
|
751
|
+
for (let _path of Object.keys(this.paths)) {
|
|
752
|
+
if (!_path.includes('.$*')) {
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
const re = new RegExp('^' + _path.replace(/\.\$\*/g, '.[^.]+') + '$');
|
|
756
|
+
if (re.test(path)) {
|
|
757
|
+
return this.paths[_path];
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
725
761
|
if (/\.\d+\.|\.\d+$/.test(path)) {
|
|
726
762
|
return getPositionalPathType(this, path);
|
|
727
763
|
}
|
|
@@ -1178,18 +1214,22 @@ Schema.prototype.plugin = function(fn, opts) {
|
|
|
1178
1214
|
* fizz.purr();
|
|
1179
1215
|
* fizz.scratch();
|
|
1180
1216
|
*
|
|
1217
|
+
* NOTE: `Schema.method()` adds instance methods to the `Schema.methods` object. You can also add instance methods directly to the `Schema.methods` object as seen in the [guide](./guide.html#methods)
|
|
1218
|
+
*
|
|
1181
1219
|
* @param {String|Object} method name
|
|
1182
1220
|
* @param {Function} [fn]
|
|
1183
1221
|
* @api public
|
|
1184
1222
|
*/
|
|
1185
1223
|
|
|
1186
|
-
Schema.prototype.method = function(name, fn) {
|
|
1224
|
+
Schema.prototype.method = function(name, fn, options) {
|
|
1187
1225
|
if (typeof name !== 'string') {
|
|
1188
|
-
for (
|
|
1226
|
+
for (const i in name) {
|
|
1189
1227
|
this.methods[i] = name[i];
|
|
1228
|
+
this.methodOptions[i] = utils.clone(options);
|
|
1190
1229
|
}
|
|
1191
1230
|
} else {
|
|
1192
1231
|
this.methods[name] = fn;
|
|
1232
|
+
this.methodOptions[name] = utils.clone(options);
|
|
1193
1233
|
}
|
|
1194
1234
|
return this;
|
|
1195
1235
|
};
|
package/lib/schematype.js
CHANGED
|
@@ -1035,6 +1035,24 @@ function handleArray(val) {
|
|
|
1035
1035
|
});
|
|
1036
1036
|
}
|
|
1037
1037
|
|
|
1038
|
+
/*!
|
|
1039
|
+
* Just like handleArray, except also allows `[]` because surprisingly
|
|
1040
|
+
* `$in: [1, []]` works fine
|
|
1041
|
+
*/
|
|
1042
|
+
|
|
1043
|
+
function handle$in(val) {
|
|
1044
|
+
var _this = this;
|
|
1045
|
+
if (!Array.isArray(val)) {
|
|
1046
|
+
return [this.castForQuery(val)];
|
|
1047
|
+
}
|
|
1048
|
+
return val.map(function(m) {
|
|
1049
|
+
if (Array.isArray(m) && m.length === 0) {
|
|
1050
|
+
return m;
|
|
1051
|
+
}
|
|
1052
|
+
return _this.castForQuery(m);
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1038
1056
|
/*!
|
|
1039
1057
|
* ignore
|
|
1040
1058
|
*/
|
|
@@ -1042,7 +1060,7 @@ function handleArray(val) {
|
|
|
1042
1060
|
SchemaType.prototype.$conditionalHandlers = {
|
|
1043
1061
|
$all: handleArray,
|
|
1044
1062
|
$eq: handleSingle,
|
|
1045
|
-
$in:
|
|
1063
|
+
$in: handle$in,
|
|
1046
1064
|
$ne: handleSingle,
|
|
1047
1065
|
$nin: handleArray,
|
|
1048
1066
|
$exists: $exists,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const utils = require('../../utils');
|
|
4
|
+
|
|
3
5
|
/*!
|
|
4
6
|
* ignore
|
|
5
7
|
*/
|
|
@@ -54,6 +56,13 @@ function applyHooks(model, schema, options) {
|
|
|
54
56
|
|
|
55
57
|
// Support hooks for custom methods
|
|
56
58
|
const customMethods = Object.keys(schema.methods);
|
|
59
|
+
const customMethodOptions = Object.assign({}, kareemOptions, {
|
|
60
|
+
// Only use `checkForPromise` for custom methods, because mongoose
|
|
61
|
+
// query thunks are not as consistent as I would like about returning
|
|
62
|
+
// a nullish value rather than the query. If a query thunk returns
|
|
63
|
+
// a query, `checkForPromise` causes infinite recursion
|
|
64
|
+
checkForPromise: true
|
|
65
|
+
});
|
|
57
66
|
for (const method of customMethods) {
|
|
58
67
|
if (!schema.s.hooks.hasHooks(method)) {
|
|
59
68
|
// Don't wrap if there are no hooks for the custom method to avoid
|
|
@@ -61,7 +70,18 @@ function applyHooks(model, schema, options) {
|
|
|
61
70
|
// so wrapping a sync method would break it.
|
|
62
71
|
continue;
|
|
63
72
|
}
|
|
64
|
-
objToDecorate[method]
|
|
65
|
-
|
|
73
|
+
const originalMethod = objToDecorate[method];
|
|
74
|
+
objToDecorate[method] = function() {
|
|
75
|
+
const args = Array.prototype.slice.call(arguments);
|
|
76
|
+
const cb = utils.last(args);
|
|
77
|
+
const argsWithoutCallback = cb == null ? args :
|
|
78
|
+
args.slice(0, args.length - 1);
|
|
79
|
+
return utils.promiseOrCallback(cb, callback => {
|
|
80
|
+
this[`$__${method}`].apply(this,
|
|
81
|
+
argsWithoutCallback.concat([callback]));
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
objToDecorate[`$__${method}`] = schema.s.hooks.
|
|
85
|
+
createWrapper(method, originalMethod, null, customMethodOptions);
|
|
66
86
|
}
|
|
67
87
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const get = require('lodash.get');
|
|
4
|
+
|
|
3
5
|
/*!
|
|
4
6
|
* Register methods for this model
|
|
5
7
|
*
|
|
@@ -20,13 +22,21 @@ module.exports = function applyMethods(model, schema) {
|
|
|
20
22
|
configurable: true
|
|
21
23
|
});
|
|
22
24
|
}
|
|
23
|
-
for (
|
|
25
|
+
for (const method of Object.keys(schema.methods)) {
|
|
26
|
+
const fn = schema.methods[method];
|
|
24
27
|
if (schema.tree.hasOwnProperty(method)) {
|
|
25
28
|
throw new Error('You have a method and a property in your schema both ' +
|
|
26
29
|
'named "' + method + '"');
|
|
27
30
|
}
|
|
28
|
-
if (
|
|
29
|
-
|
|
31
|
+
if (schema.reserved[method] &&
|
|
32
|
+
!get(schema, `methodOptions.${method}.suppressWarning`, false)) {
|
|
33
|
+
console.warn(`mongoose: the method name "${method}" is used by mongoose ` +
|
|
34
|
+
'internally, overwriting it may cause bugs. If you\'re sure you know ' +
|
|
35
|
+
'what you\'re doing, you can suppress this error by using ' +
|
|
36
|
+
`\`schema.method('${method}', fn, { suppressWarning: true })\`.`);
|
|
37
|
+
}
|
|
38
|
+
if (typeof fn === 'function') {
|
|
39
|
+
model.prototype[method] = fn;
|
|
30
40
|
} else {
|
|
31
41
|
apply(method, schema);
|
|
32
42
|
}
|
|
@@ -34,7 +44,7 @@ module.exports = function applyMethods(model, schema) {
|
|
|
34
44
|
|
|
35
45
|
// Recursively call `applyMethods()` on child schemas
|
|
36
46
|
model.$appliedMethods = true;
|
|
37
|
-
for (
|
|
47
|
+
for (let i = 0; i < schema.childSchemas.length; ++i) {
|
|
38
48
|
if (schema.childSchemas[i].model.$appliedMethods) {
|
|
39
49
|
continue;
|
|
40
50
|
}
|
|
@@ -205,7 +205,7 @@ function walkUpdatePath(schema, obj, op, options, context, pref) {
|
|
|
205
205
|
(utils.isObject(val) && Object.keys(val).length === 0);
|
|
206
206
|
}
|
|
207
207
|
} else {
|
|
208
|
-
var checkPath = (key === '$each' || key === '$or' || key === '$and') ?
|
|
208
|
+
var checkPath = (key === '$each' || key === '$or' || key === '$and' || key === '$in') ?
|
|
209
209
|
pref : prefix + key;
|
|
210
210
|
schematype = schema._getSchema(checkPath);
|
|
211
211
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const helpers = require('../../queryhelpers');
|
|
4
|
+
|
|
5
|
+
module.exports = completeMany;
|
|
6
|
+
|
|
7
|
+
/*!
|
|
8
|
+
* Given a model and an array of docs, hydrates all the docs to be instances
|
|
9
|
+
* of the model. Used to initialize docs returned from the db from `find()`
|
|
10
|
+
*
|
|
11
|
+
* @param {Model} model
|
|
12
|
+
* @param {Array} docs
|
|
13
|
+
* @param {Object} fields the projection used, including `select` from schemas
|
|
14
|
+
* @param {Object} userProvidedFields the user-specified projection
|
|
15
|
+
* @param {Object} opts
|
|
16
|
+
* @param {Array} [opts.populated]
|
|
17
|
+
* @param {ClientSession} [opts.session]
|
|
18
|
+
* @param {Function} callback
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
function completeMany(model, docs, fields, userProvidedFields, opts, callback) {
|
|
22
|
+
const arr = [];
|
|
23
|
+
let count = docs.length;
|
|
24
|
+
const len = count;
|
|
25
|
+
let error = null;
|
|
26
|
+
|
|
27
|
+
function init(_error) {
|
|
28
|
+
if (_error != null) {
|
|
29
|
+
error = error || _error;
|
|
30
|
+
}
|
|
31
|
+
if (error != null) {
|
|
32
|
+
--count || process.nextTick(() => callback(error));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
--count || process.nextTick(() => callback(error, arr));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < len; ++i) {
|
|
39
|
+
arr[i] = helpers.createModel(model, docs[i], fields, userProvidedFields);
|
|
40
|
+
try {
|
|
41
|
+
arr[i].init(docs[i], opts, init);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
init(error);
|
|
44
|
+
}
|
|
45
|
+
arr[i].$session(opts.session);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/lib/types/buffer.js
CHANGED
|
@@ -167,7 +167,7 @@ MongooseBuffer.mixin = {
|
|
|
167
167
|
'writeFloat writeDouble fill ' +
|
|
168
168
|
'utf8Write binaryWrite asciiWrite set ' +
|
|
169
169
|
|
|
170
|
-
// node >= 0.5
|
|
170
|
+
// node >= 0.5
|
|
171
171
|
'writeUInt16LE writeUInt16BE writeUInt32LE writeUInt32BE ' +
|
|
172
172
|
'writeInt16LE writeInt16BE writeInt32LE writeInt32BE ' +
|
|
173
173
|
'writeFloatLE writeFloatBE writeDoubleLE writeDoubleBE'
|
|
@@ -12,6 +12,18 @@ const utils = require('../utils');
|
|
|
12
12
|
const Document = require('../document');
|
|
13
13
|
const getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
|
|
14
14
|
|
|
15
|
+
/*!
|
|
16
|
+
* ignore
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
class CoreMongooseArray extends Array {
|
|
20
|
+
get isMongooseArray() {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
remove() {}
|
|
25
|
+
}
|
|
26
|
+
|
|
15
27
|
/**
|
|
16
28
|
* DocumentArray constructor
|
|
17
29
|
*
|
|
@@ -25,11 +37,13 @@ const getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByVal
|
|
|
25
37
|
*/
|
|
26
38
|
|
|
27
39
|
function MongooseDocumentArray(values, path, doc) {
|
|
28
|
-
|
|
40
|
+
// TODO: replace this with `new CoreMongooseArray().concat()` when we remove
|
|
41
|
+
// support for node 4.x and 5.x, see https://i.imgur.com/UAAHk4S.png
|
|
42
|
+
var arr = new CoreMongooseArray();
|
|
43
|
+
if (Array.isArray(values)) values.forEach(v => arr.push(v));
|
|
29
44
|
arr._path = path;
|
|
30
45
|
|
|
31
46
|
var props = {
|
|
32
|
-
isMongooseArray: true,
|
|
33
47
|
isMongooseDocumentArray: true,
|
|
34
48
|
validators: [],
|
|
35
49
|
_atomics: {},
|
package/lib/types/embedded.js
CHANGED
|
@@ -107,7 +107,20 @@ EmbeddedDocument.prototype.populate = function() {
|
|
|
107
107
|
* @api private
|
|
108
108
|
*/
|
|
109
109
|
|
|
110
|
-
EmbeddedDocument.prototype.save = function(fn) {
|
|
110
|
+
EmbeddedDocument.prototype.save = function(options, fn) {
|
|
111
|
+
if (typeof options === 'function') {
|
|
112
|
+
fn = options;
|
|
113
|
+
options = {};
|
|
114
|
+
}
|
|
115
|
+
options = options || {};
|
|
116
|
+
|
|
117
|
+
if (!options.suppressWarning) {
|
|
118
|
+
console.warn('mongoose: calling `save()` on a subdoc does **not** save ' +
|
|
119
|
+
'the document to MongoDB, it only runs save middleware. ' +
|
|
120
|
+
'Use `subdoc.save({ suppressWarning: true })` to hide this warning ' +
|
|
121
|
+
'if you\'re sure this behavior is right for your app.');
|
|
122
|
+
}
|
|
123
|
+
|
|
111
124
|
return utils.promiseOrCallback(fn, cb => {
|
|
112
125
|
this.$__save(cb);
|
|
113
126
|
});
|
|
@@ -274,6 +287,25 @@ EmbeddedDocument.prototype.$markValid = function(path) {
|
|
|
274
287
|
}
|
|
275
288
|
};
|
|
276
289
|
|
|
290
|
+
/*!
|
|
291
|
+
* ignore
|
|
292
|
+
*/
|
|
293
|
+
|
|
294
|
+
EmbeddedDocument.prototype.$ignore = function(path) {
|
|
295
|
+
Document.prototype.$ignore.call(this, path);
|
|
296
|
+
|
|
297
|
+
if (!this.__parent) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
var index = this.__index;
|
|
302
|
+
if (typeof index !== 'undefined') {
|
|
303
|
+
var parentPath = this.__parentArray._path;
|
|
304
|
+
var fullPath = [parentPath, index, path].join('.');
|
|
305
|
+
this.__parent.$ignore(fullPath);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
|
|
277
309
|
/**
|
|
278
310
|
* Checks if a path is invalid
|
|
279
311
|
*
|
package/lib/types/index.js
CHANGED