mongoose 5.7.7 → 5.7.8
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/History.md +11 -0
- package/lib/aggregate.js +3 -3
- package/lib/cursor/AggregationCursor.js +10 -0
- package/lib/document.js +39 -2
- package/lib/model.js +3 -2
- package/lib/options/SchemaTypeOptions.js +10 -5
- package/lib/queryhelpers.js +1 -1
- package/lib/schema/SingleNestedPath.js +1 -0
- package/lib/schema/array.js +2 -2
- package/lib/schema/documentarray.js +13 -0
- package/lib/schema.js +7 -13
- package/lib/schematype.js +2 -2
- package/lib/types/core_array.js +0 -18
- package/lib/types/documentarray.js +81 -0
- package/package.json +2 -5
package/History.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
5.7.8 / 2019-11-04
|
|
2
|
+
==================
|
|
3
|
+
* fix(document): allow manually populating path within document array #8273
|
|
4
|
+
* fix(populate): update top-level `populated()` when updating document array with populated subpaths #8265
|
|
5
|
+
* fix(cursor): throw error when using aggregation cursor as async iterator #8280
|
|
6
|
+
* fix(schema): retain `_id: false` in schema after nesting in another schema #8274
|
|
7
|
+
* fix(document): make Document class an event emitter to support defining documents without models in node #8272
|
|
8
|
+
* docs: document return types for `.discriminator()` #8287
|
|
9
|
+
* docs(connection): add note about exporting schemas, not models, in multi connection paradigm #8275
|
|
10
|
+
* docs: clarify that transforms defined in `toObject()` options are applied to subdocs #8260
|
|
11
|
+
|
|
1
12
|
5.7.7 / 2019-10-24
|
|
2
13
|
==================
|
|
3
14
|
* fix(populate): make populate virtual consistently an empty array if local field is only empty arrays #8230
|
package/lib/aggregate.js
CHANGED
|
@@ -1011,20 +1011,20 @@ Aggregate.prototype.catch = function(reject) {
|
|
|
1011
1011
|
|
|
1012
1012
|
/**
|
|
1013
1013
|
* Returns an asyncIterator for use with [`for/await/of` loops](http://bit.ly/async-iterators)
|
|
1014
|
-
* This function *only* works for `find()` queries.
|
|
1015
1014
|
* You do not need to call this function explicitly, the JavaScript runtime
|
|
1016
1015
|
* will call it for you.
|
|
1017
1016
|
*
|
|
1018
1017
|
* ####Example
|
|
1019
1018
|
*
|
|
1020
|
-
*
|
|
1019
|
+
* const agg = Model.aggregate([{ $match: { age: { $gte: 25 } } }]);
|
|
1020
|
+
* for await (const doc of agg) {
|
|
1021
1021
|
* console.log(doc.name);
|
|
1022
1022
|
* }
|
|
1023
1023
|
*
|
|
1024
1024
|
* Node.js 10.x supports async iterators natively without any flags. You can
|
|
1025
1025
|
* enable async iterators in Node.js 8.x using the [`--harmony_async_iteration` flag](https://github.com/tc39/proposal-async-iteration/issues/117#issuecomment-346695187).
|
|
1026
1026
|
*
|
|
1027
|
-
* **Note:** This function is not if `Symbol.asyncIterator` is undefined. If
|
|
1027
|
+
* **Note:** This function is not set if `Symbol.asyncIterator` is undefined. If
|
|
1028
1028
|
* `Symbol.asyncIterator` is undefined, that means your Node.js version does not
|
|
1029
1029
|
* support async iterators.
|
|
1030
1030
|
*
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
+
const MongooseError = require('../error/mongooseError');
|
|
7
8
|
const Readable = require('stream').Readable;
|
|
8
9
|
const eachAsync = require('../helpers/cursor/eachAsync');
|
|
9
10
|
const util = require('util');
|
|
@@ -94,6 +95,15 @@ AggregationCursor.prototype._read = function() {
|
|
|
94
95
|
});
|
|
95
96
|
};
|
|
96
97
|
|
|
98
|
+
if (Symbol.asyncIterator != null) {
|
|
99
|
+
const msg = 'Mongoose does not support using async iterators with an ' +
|
|
100
|
+
'existing aggregation cursor. See http://bit.ly/mongoose-async-iterate-aggregation';
|
|
101
|
+
|
|
102
|
+
AggregationCursor.prototype[Symbol.asyncIterator] = function() {
|
|
103
|
+
throw new MongooseError(msg);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
97
107
|
/**
|
|
98
108
|
* Registers a transform function which subsequently maps documents retrieved
|
|
99
109
|
* via the streams interface or `.next()`
|
package/lib/document.js
CHANGED
|
@@ -184,6 +184,10 @@ utils.each(
|
|
|
184
184
|
|
|
185
185
|
Document.prototype.constructor = Document;
|
|
186
186
|
|
|
187
|
+
for (const i in EventEmitter.prototype) {
|
|
188
|
+
Document[i] = EventEmitter.prototype[i];
|
|
189
|
+
}
|
|
190
|
+
|
|
187
191
|
/**
|
|
188
192
|
* The documents schema.
|
|
189
193
|
*
|
|
@@ -1163,6 +1167,21 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1163
1167
|
val = schema.applySetters(val, this, false, priorVal);
|
|
1164
1168
|
}
|
|
1165
1169
|
|
|
1170
|
+
if (schema.$isMongooseDocumentArray &&
|
|
1171
|
+
Array.isArray(val) &&
|
|
1172
|
+
val.length > 0 &&
|
|
1173
|
+
val[0] != null &&
|
|
1174
|
+
val[0].$__ != null &&
|
|
1175
|
+
val[0].$__.populated != null) {
|
|
1176
|
+
const populatedPaths = Object.keys(val[0].$__.populated);
|
|
1177
|
+
for (const populatedPath of populatedPaths) {
|
|
1178
|
+
this.populated(path + '.' + populatedPath,
|
|
1179
|
+
val.map(v => v.populated(populatedPath)),
|
|
1180
|
+
val[0].$__.populated[populatedPath].options);
|
|
1181
|
+
}
|
|
1182
|
+
didPopulate = true;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1166
1185
|
if (!didPopulate && this.$__.populated) {
|
|
1167
1186
|
delete this.$__.populated[path];
|
|
1168
1187
|
}
|
|
@@ -2970,7 +2989,6 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
2970
2989
|
*
|
|
2971
2990
|
* If you want to skip transformations, use `transform: false`:
|
|
2972
2991
|
*
|
|
2973
|
-
* if (!schema.options.toObject) schema.options.toObject = {};
|
|
2974
2992
|
* schema.options.toObject.hide = '_id';
|
|
2975
2993
|
* schema.options.toObject.transform = function (doc, ret, options) {
|
|
2976
2994
|
* if (options.hide) {
|
|
@@ -2986,7 +3004,26 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
2986
3004
|
* doc.toObject({ hide: 'secret _id', transform: false });// { _id: 'anId', secret: 47, name: 'Wreck-it Ralph' }
|
|
2987
3005
|
* doc.toObject({ hide: 'secret _id', transform: true }); // { name: 'Wreck-it Ralph' }
|
|
2988
3006
|
*
|
|
2989
|
-
*
|
|
3007
|
+
* If you pass a transform in `toObject()` options, Mongoose will apply the transform
|
|
3008
|
+
* to [subdocuments](/docs/subdocs.html) in addition to the top-level document.
|
|
3009
|
+
* Similarly, `transform: false` skips transforms for all subdocuments.
|
|
3010
|
+
* Note that this is behavior is different for transforms defined in the schema:
|
|
3011
|
+
* if you define a transform in `schema.options.toObject.transform`, that transform
|
|
3012
|
+
* will **not** apply to subdocuments.
|
|
3013
|
+
*
|
|
3014
|
+
* const memberSchema = new Schema({ name: String, email: String });
|
|
3015
|
+
* const groupSchema = new Schema({ members: [memberSchema], name: String, email });
|
|
3016
|
+
* const Group = mongoose.model('Group', groupSchema);
|
|
3017
|
+
*
|
|
3018
|
+
* const doc = new Group({
|
|
3019
|
+
* name: 'Engineering',
|
|
3020
|
+
* email: 'dev@mongoosejs.io',
|
|
3021
|
+
* members: [{ name: 'Val', email: 'val@mongoosejs.io' }]
|
|
3022
|
+
* });
|
|
3023
|
+
*
|
|
3024
|
+
* // Removes `email` from both top-level document **and** array elements
|
|
3025
|
+
* // { name: 'Engineering', members: [{ name: 'Val' }] }
|
|
3026
|
+
* doc.toObject({ transform: (doc, ret) => { delete ret.email; return ret; } });
|
|
2990
3027
|
*
|
|
2991
3028
|
* Transforms, like all of these options, are also available for `toJSON`. See [this guide to `JSON.stringify()`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html) to learn why `toJSON()` and `toObject()` are separate functions.
|
|
2992
3029
|
*
|
package/lib/model.js
CHANGED
|
@@ -1067,6 +1067,7 @@ Model.exists = function exists(filter, options, callback) {
|
|
|
1067
1067
|
* @param {String} name discriminator model name
|
|
1068
1068
|
* @param {Schema} schema discriminator model schema
|
|
1069
1069
|
* @param {String} [value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
|
|
1070
|
+
* @return {Model} The newly created discriminator model
|
|
1070
1071
|
* @api public
|
|
1071
1072
|
*/
|
|
1072
1073
|
|
|
@@ -1149,7 +1150,7 @@ for (const i in EventEmitter.prototype) {
|
|
|
1149
1150
|
*
|
|
1150
1151
|
* Mongoose calls this function automatically when a model is created using
|
|
1151
1152
|
* [`mongoose.model()`](/docs/api.html#mongoose_Mongoose-model) or
|
|
1152
|
-
*
|
|
1153
|
+
* [`connection.model()`](/docs/api.html#connection_Connection-model), so you
|
|
1153
1154
|
* don't need to call it. This function is also idempotent, so you may call it
|
|
1154
1155
|
* to get back a promise that will resolve when your indexes are finished
|
|
1155
1156
|
* building as an alternative to [`MyModel.on('index')`](/docs/guide.html#indexes)
|
|
@@ -3411,7 +3412,7 @@ Model.bulkWrite = function(ops, options, callback) {
|
|
|
3411
3412
|
* var mongooseCandy = Candy.hydrate({ _id: '54108337212ffb6d459f854c', type: 'jelly bean' });
|
|
3412
3413
|
*
|
|
3413
3414
|
* @param {Object} obj
|
|
3414
|
-
* @return {
|
|
3415
|
+
* @return {Document} document instance
|
|
3415
3416
|
* @api public
|
|
3416
3417
|
*/
|
|
3417
3418
|
|
|
@@ -107,7 +107,8 @@ Object.defineProperty(SchemaTypeOptions.prototype, 'ref', opts);
|
|
|
107
107
|
Object.defineProperty(SchemaTypeOptions.prototype, 'select', opts);
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
|
-
* If truthy, Mongoose will
|
|
110
|
+
* If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will
|
|
111
|
+
* build an index on this path when the model is
|
|
111
112
|
* compiled.
|
|
112
113
|
*
|
|
113
114
|
* @api public
|
|
@@ -120,7 +121,8 @@ Object.defineProperty(SchemaTypeOptions.prototype, 'select', opts);
|
|
|
120
121
|
Object.defineProperty(SchemaTypeOptions.prototype, 'index', opts);
|
|
121
122
|
|
|
122
123
|
/**
|
|
123
|
-
* If truthy, Mongoose
|
|
124
|
+
* If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose
|
|
125
|
+
* will build a unique index on this path when the
|
|
124
126
|
* model is compiled. [The `unique` option is **not** a validator](/docs/validation.html#the-unique-option-is-not-a-validator).
|
|
125
127
|
*
|
|
126
128
|
* @api public
|
|
@@ -133,7 +135,8 @@ Object.defineProperty(SchemaTypeOptions.prototype, 'index', opts);
|
|
|
133
135
|
Object.defineProperty(SchemaTypeOptions.prototype, 'unique', opts);
|
|
134
136
|
|
|
135
137
|
/**
|
|
136
|
-
* If truthy, Mongoose will
|
|
138
|
+
* If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will
|
|
139
|
+
* disallow changes to this path once the document
|
|
137
140
|
* is saved to the database for the first time. Read more about [immutability in Mongoose here](http://thecodebarbarian.com/whats-new-in-mongoose-5-6-immutable-properties.html).
|
|
138
141
|
*
|
|
139
142
|
* @api public
|
|
@@ -146,7 +149,8 @@ Object.defineProperty(SchemaTypeOptions.prototype, 'unique', opts);
|
|
|
146
149
|
Object.defineProperty(SchemaTypeOptions.prototype, 'immutable', opts);
|
|
147
150
|
|
|
148
151
|
/**
|
|
149
|
-
* If truthy, Mongoose will
|
|
152
|
+
* If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose will
|
|
153
|
+
* build a sparse index on this path.
|
|
150
154
|
*
|
|
151
155
|
* @api public
|
|
152
156
|
* @property sparse
|
|
@@ -158,7 +162,8 @@ Object.defineProperty(SchemaTypeOptions.prototype, 'immutable', opts);
|
|
|
158
162
|
Object.defineProperty(SchemaTypeOptions.prototype, 'sparse', opts);
|
|
159
163
|
|
|
160
164
|
/**
|
|
161
|
-
* If truthy, Mongoose
|
|
165
|
+
* If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), Mongoose
|
|
166
|
+
* will build a text index on this path.
|
|
162
167
|
*
|
|
163
168
|
* @api public
|
|
164
169
|
* @property text
|
package/lib/queryhelpers.js
CHANGED
|
@@ -107,7 +107,7 @@ exports.getDiscriminatorByValue = getDiscriminatorByValue;
|
|
|
107
107
|
* @param {Object} doc
|
|
108
108
|
* @param {Object} fields
|
|
109
109
|
*
|
|
110
|
-
* @return {
|
|
110
|
+
* @return {Document}
|
|
111
111
|
*/
|
|
112
112
|
exports.createModel = function createModel(model, doc, fields, userProvidedFields) {
|
|
113
113
|
model.hooks.execPreSync('createModel', doc);
|
|
@@ -280,6 +280,7 @@ SingleNestedPath.prototype.doValidateSync = function(value, scope, options) {
|
|
|
280
280
|
* @param {String} name
|
|
281
281
|
* @param {Schema} schema fields to add to the schema for instances of this sub-class
|
|
282
282
|
* @param {String} [value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
|
|
283
|
+
* @return {Function} the constructor Mongoose will use for creating instances of this discriminator model
|
|
283
284
|
* @see discriminators /docs/discriminators.html
|
|
284
285
|
* @api public
|
|
285
286
|
*/
|
package/lib/schema/array.js
CHANGED
|
@@ -196,8 +196,8 @@ SchemaArray.prototype.checkRequired = function checkRequired(value, doc) {
|
|
|
196
196
|
*/
|
|
197
197
|
|
|
198
198
|
SchemaArray.prototype.enum = function() {
|
|
199
|
-
let arr = this;
|
|
200
|
-
while (true) {
|
|
199
|
+
let arr = this;
|
|
200
|
+
while (true) {
|
|
201
201
|
const instance = get(arr, 'caster.instance');
|
|
202
202
|
if (instance === 'Array') {
|
|
203
203
|
arr = arr.caster;
|
|
@@ -9,6 +9,7 @@ const CastError = require('../error/cast');
|
|
|
9
9
|
const EventEmitter = require('events').EventEmitter;
|
|
10
10
|
const SchemaType = require('../schematype');
|
|
11
11
|
const discriminator = require('../helpers/model/discriminator');
|
|
12
|
+
const get = require('../helpers/get');
|
|
12
13
|
const util = require('util');
|
|
13
14
|
const utils = require('../utils');
|
|
14
15
|
const getConstructor = require('../helpers/discriminator/getConstructor');
|
|
@@ -54,6 +55,17 @@ function DocumentArrayPath(key, schema, options, schemaOptions) {
|
|
|
54
55
|
return arr;
|
|
55
56
|
});
|
|
56
57
|
}
|
|
58
|
+
|
|
59
|
+
const parentSchemaType = this;
|
|
60
|
+
this.$embeddedSchemaType = new SchemaType(key + '.$', {
|
|
61
|
+
required: get(this, 'schemaOptions.required', false)
|
|
62
|
+
});
|
|
63
|
+
this.$embeddedSchemaType.cast = function(value, doc, init) {
|
|
64
|
+
return parentSchemaType.cast(value, doc, init)[0];
|
|
65
|
+
};
|
|
66
|
+
this.$embeddedSchemaType.$isMongooseDocumentArrayElement = true;
|
|
67
|
+
this.$embeddedSchemaType.caster = this.Constructor;
|
|
68
|
+
this.$embeddedSchemaType.schema = this.schema;
|
|
57
69
|
}
|
|
58
70
|
|
|
59
71
|
/**
|
|
@@ -135,6 +147,7 @@ function _createConstructor(schema, options, baseClass) {
|
|
|
135
147
|
* @param {Schema} schema fields to add to the schema for instances of this sub-class
|
|
136
148
|
* @param {String} [value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
|
|
137
149
|
* @see discriminators /docs/discriminators.html
|
|
150
|
+
* @return {Function} the constructor Mongoose will use for creating instances of this discriminator model
|
|
138
151
|
* @api public
|
|
139
152
|
*/
|
|
140
153
|
|
package/lib/schema.js
CHANGED
|
@@ -402,7 +402,6 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
402
402
|
// the `_id` option. This behavior never worked before 5.4.11 but numerous
|
|
403
403
|
// codebases use it (see gh-7516, gh-7512).
|
|
404
404
|
if (obj._id === false && prefix == null) {
|
|
405
|
-
delete obj._id;
|
|
406
405
|
this.options._id = false;
|
|
407
406
|
}
|
|
408
407
|
|
|
@@ -417,6 +416,10 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
417
416
|
throw new TypeError('Invalid value for schema path `' + fullPath +
|
|
418
417
|
'`, got value "' + obj[key] + '"');
|
|
419
418
|
}
|
|
419
|
+
// Retain `_id: false` but don't set it as a path, re: gh-8274.
|
|
420
|
+
if (key === '_id' && obj[key] === false) {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
420
423
|
|
|
421
424
|
if (Array.isArray(obj[key]) && obj[key].length === 1 && obj[key][0] == null) {
|
|
422
425
|
throw new TypeError('Invalid value for schema Array path `' + fullPath +
|
|
@@ -1179,16 +1182,7 @@ function getPositionalPathType(self, path) {
|
|
|
1179
1182
|
|
|
1180
1183
|
if (i === last && val && !/\D/.test(subpath)) {
|
|
1181
1184
|
if (val.$isMongooseDocumentArray) {
|
|
1182
|
-
|
|
1183
|
-
val = new SchemaType(subpath, {
|
|
1184
|
-
required: get(val, 'schemaOptions.required', false)
|
|
1185
|
-
});
|
|
1186
|
-
val.cast = function(value, doc, init) {
|
|
1187
|
-
return oldVal.cast(value, doc, init)[0];
|
|
1188
|
-
};
|
|
1189
|
-
val.$isMongooseDocumentArrayElement = true;
|
|
1190
|
-
val.caster = oldVal.caster;
|
|
1191
|
-
val.schema = oldVal.schema;
|
|
1185
|
+
val = val.$embeddedSchemaType;
|
|
1192
1186
|
} else if (val instanceof MongooseTypes.Array) {
|
|
1193
1187
|
// StringSchema, NumberSchema, etc
|
|
1194
1188
|
val = val.caster;
|
|
@@ -1637,8 +1631,8 @@ Schema.prototype.indexes = function() {
|
|
|
1637
1631
|
* @param {String|Model} [options.ref] model name or model instance. Marks this as a [populate virtual](populate.html#populate-virtuals).
|
|
1638
1632
|
* @param {String|Function} [options.localField] Required for populate virtuals. See [populate virtual docs](populate.html#populate-virtuals) for more information.
|
|
1639
1633
|
* @param {String|Function} [options.foreignField] Required for populate virtuals. See [populate virtual docs](populate.html#populate-virtuals) for more information.
|
|
1640
|
-
* @param {Boolean|Function} [options.justOne=false] Only works with populate virtuals. If truthy, will be a single doc or `null`. Otherwise, the populate virtual will be an array.
|
|
1641
|
-
* @param {Boolean} [options.count=false] Only works with populate virtuals. If truthy, this populate virtual will contain the number of documents rather than the documents themselves when you `populate()`.
|
|
1634
|
+
* @param {Boolean|Function} [options.justOne=false] Only works with populate virtuals. If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), will be a single doc or `null`. Otherwise, the populate virtual will be an array.
|
|
1635
|
+
* @param {Boolean} [options.count=false] Only works with populate virtuals. If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), this populate virtual will contain the number of documents rather than the documents themselves when you `populate()`.
|
|
1642
1636
|
* @return {VirtualType}
|
|
1643
1637
|
*/
|
|
1644
1638
|
|
package/lib/schematype.js
CHANGED
|
@@ -664,7 +664,7 @@ SchemaType.prototype.get = function(fn) {
|
|
|
664
664
|
* Product.on('error', handleError);
|
|
665
665
|
*
|
|
666
666
|
* @param {RegExp|Function|Object} obj validator function, or hash describing options
|
|
667
|
-
* @param {Function} [obj.validator] validator function. If the validator function returns `undefined` or a truthy value, validation succeeds. If it returns falsy (except `undefined`) or throws an error, validation fails.
|
|
667
|
+
* @param {Function} [obj.validator] validator function. If the validator function returns `undefined` or a truthy value, validation succeeds. If it returns [falsy](https://masteringjs.io/tutorials/fundamentals/falsy) (except `undefined`) or throws an error, validation fails.
|
|
668
668
|
* @param {String|Function} [obj.message] optional error message. If function, should return the error message as a string
|
|
669
669
|
* @param {Boolean} [obj.propsParameter=false] If true, Mongoose will pass the validator properties object (with the `validator` function, `message`, etc.) as the 2nd arg to the validator function. This is disabled by default because many validators [rely on positional args](https://github.com/chriso/validator.js#validators), so turning this on may cause unpredictable behavior in external validators.
|
|
670
670
|
* @param {String|Function} [errorMsg] optional error message. If function, should return the error message as a string
|
|
@@ -1265,7 +1265,7 @@ SchemaType._isRef = function(self, value, doc, init) {
|
|
|
1265
1265
|
// - setting / pushing values after population
|
|
1266
1266
|
const path = doc.$__fullPath(self.path);
|
|
1267
1267
|
const owner = doc.ownerDocument ? doc.ownerDocument() : doc;
|
|
1268
|
-
ref = owner.populated(path);
|
|
1268
|
+
ref = owner.populated(path) || doc.populated(self.path);
|
|
1269
1269
|
}
|
|
1270
1270
|
|
|
1271
1271
|
if (ref) {
|
package/lib/types/core_array.js
CHANGED
|
@@ -634,24 +634,6 @@ class CoreMongooseArray extends Array {
|
|
|
634
634
|
undefined, { skipDocumentArrayCast: true });
|
|
635
635
|
const ret = [].push.apply(this, values);
|
|
636
636
|
|
|
637
|
-
// If this is a document array, each element may contain single
|
|
638
|
-
// populated paths, so we need to modify the top-level document's
|
|
639
|
-
// populated cache. See gh-8247.
|
|
640
|
-
if (this.isMongooseDocumentArray && parent.$__.populated != null) {
|
|
641
|
-
const populatedPaths = Object.keys(parent.$__.populated).
|
|
642
|
-
filter(p => p.startsWith(this[arrayPathSymbol] + '.'));
|
|
643
|
-
|
|
644
|
-
for (const path of populatedPaths) {
|
|
645
|
-
const remnant = path.slice((this[arrayPathSymbol] + '.').length);
|
|
646
|
-
if (!Array.isArray(parent.$__.populated[path].value)) {
|
|
647
|
-
continue;
|
|
648
|
-
}
|
|
649
|
-
for (const val of values) {
|
|
650
|
-
parent.$__.populated[path].value.push(val.populated(remnant));
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
637
|
this._registerAtomic('$push', values);
|
|
656
638
|
this._markModified();
|
|
657
639
|
return ret;
|
|
@@ -172,6 +172,64 @@ class CoreDocumentArray extends CoreMongooseArray {
|
|
|
172
172
|
}));
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
|
|
177
|
+
*
|
|
178
|
+
* @param {Object} [args...]
|
|
179
|
+
* @api public
|
|
180
|
+
* @method push
|
|
181
|
+
* @memberOf MongooseDocumentArray
|
|
182
|
+
*/
|
|
183
|
+
|
|
184
|
+
push() {
|
|
185
|
+
const ret = super.push.apply(this, arguments);
|
|
186
|
+
|
|
187
|
+
_updateParentPopulated(this);
|
|
188
|
+
|
|
189
|
+
return ret;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Pulls items from the array atomically.
|
|
194
|
+
*
|
|
195
|
+
* @param {Object} [args...]
|
|
196
|
+
* @api public
|
|
197
|
+
* @method pull
|
|
198
|
+
* @memberOf MongooseDocumentArray
|
|
199
|
+
*/
|
|
200
|
+
|
|
201
|
+
pull() {
|
|
202
|
+
const ret = super.pull.apply(this, arguments);
|
|
203
|
+
|
|
204
|
+
_updateParentPopulated(this);
|
|
205
|
+
|
|
206
|
+
return ret;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Wraps [`Array#shift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
shift() {
|
|
214
|
+
const ret = super.shift.apply(this, arguments);
|
|
215
|
+
|
|
216
|
+
_updateParentPopulated(this);
|
|
217
|
+
|
|
218
|
+
return ret;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Wraps [`Array#splice`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting.
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
splice() {
|
|
226
|
+
const ret = super.splice.apply(this, arguments);
|
|
227
|
+
|
|
228
|
+
_updateParentPopulated(this);
|
|
229
|
+
|
|
230
|
+
return ret;
|
|
231
|
+
}
|
|
232
|
+
|
|
175
233
|
/**
|
|
176
234
|
* Helper for console.log
|
|
177
235
|
*
|
|
@@ -254,6 +312,29 @@ if (util.inspect.custom) {
|
|
|
254
312
|
CoreDocumentArray.prototype.inspect;
|
|
255
313
|
}
|
|
256
314
|
|
|
315
|
+
/*!
|
|
316
|
+
* If this is a document array, each element may contain single
|
|
317
|
+
* populated paths, so we need to modify the top-level document's
|
|
318
|
+
* populated cache. See gh-8247, gh-8265.
|
|
319
|
+
*/
|
|
320
|
+
|
|
321
|
+
function _updateParentPopulated(arr) {
|
|
322
|
+
const parent = arr[arrayParentSymbol];
|
|
323
|
+
if (parent.$__.populated != null) {
|
|
324
|
+
const populatedPaths = Object.keys(parent.$__.populated).
|
|
325
|
+
filter(p => p.startsWith(arr[arrayPathSymbol] + '.'));
|
|
326
|
+
|
|
327
|
+
for (const path of populatedPaths) {
|
|
328
|
+
const remnant = path.slice((arr[arrayPathSymbol] + '.').length);
|
|
329
|
+
if (!Array.isArray(parent.$__.populated[path].value)) {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
parent.$__.populated[path].value = arr.map(val => val.populated(remnant));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
257
338
|
/**
|
|
258
339
|
* DocumentArray constructor
|
|
259
340
|
*
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongoose",
|
|
3
3
|
"description": "Mongoose MongoDB ODM",
|
|
4
|
-
"version": "5.7.
|
|
4
|
+
"version": "5.7.8",
|
|
5
5
|
"author": "Guillermo Rauch <guillermo@learnboost.com>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mongodb",
|
|
@@ -102,10 +102,6 @@
|
|
|
102
102
|
},
|
|
103
103
|
"rules": {
|
|
104
104
|
"comma-style": "error",
|
|
105
|
-
"consistent-this": [
|
|
106
|
-
"error",
|
|
107
|
-
"_this"
|
|
108
|
-
],
|
|
109
105
|
"indent": [
|
|
110
106
|
"error",
|
|
111
107
|
2,
|
|
@@ -118,6 +114,7 @@
|
|
|
118
114
|
"no-buffer-constructor": "warn",
|
|
119
115
|
"no-console": "off",
|
|
120
116
|
"no-multi-spaces": "error",
|
|
117
|
+
"no-constant-condition": "off",
|
|
121
118
|
"func-call-spacing": "error",
|
|
122
119
|
"no-trailing-spaces": "error",
|
|
123
120
|
"quotes": [
|