@depup/mongoose 9.1.3-depup.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/LICENSE.md +22 -0
- package/README.md +397 -0
- package/SECURITY.md +1 -0
- package/eslint.config.mjs +198 -0
- package/index.js +64 -0
- package/lib/aggregate.js +1189 -0
- package/lib/cast/bigint.js +46 -0
- package/lib/cast/boolean.js +32 -0
- package/lib/cast/date.js +41 -0
- package/lib/cast/decimal128.js +39 -0
- package/lib/cast/double.js +50 -0
- package/lib/cast/int32.js +36 -0
- package/lib/cast/number.js +42 -0
- package/lib/cast/objectid.js +29 -0
- package/lib/cast/string.js +37 -0
- package/lib/cast/uuid.js +35 -0
- package/lib/cast.js +436 -0
- package/lib/collection.js +321 -0
- package/lib/connection.js +1855 -0
- package/lib/connectionState.js +26 -0
- package/lib/constants.js +73 -0
- package/lib/cursor/aggregationCursor.js +466 -0
- package/lib/cursor/changeStream.js +198 -0
- package/lib/cursor/queryCursor.js +622 -0
- package/lib/document.js +5521 -0
- package/lib/driver.js +15 -0
- package/lib/drivers/SPEC.md +4 -0
- package/lib/drivers/node-mongodb-native/bulkWriteResult.js +5 -0
- package/lib/drivers/node-mongodb-native/collection.js +393 -0
- package/lib/drivers/node-mongodb-native/connection.js +506 -0
- package/lib/drivers/node-mongodb-native/index.js +10 -0
- package/lib/error/browserMissingSchema.js +29 -0
- package/lib/error/bulkSaveIncompleteError.js +44 -0
- package/lib/error/bulkWriteError.js +41 -0
- package/lib/error/cast.js +158 -0
- package/lib/error/createCollectionsError.js +26 -0
- package/lib/error/divergentArray.js +40 -0
- package/lib/error/eachAsyncMultiError.js +41 -0
- package/lib/error/index.js +237 -0
- package/lib/error/invalidSchemaOption.js +32 -0
- package/lib/error/messages.js +47 -0
- package/lib/error/missingSchema.js +33 -0
- package/lib/error/mongooseError.js +13 -0
- package/lib/error/notFound.js +47 -0
- package/lib/error/objectExpected.js +31 -0
- package/lib/error/objectParameter.js +31 -0
- package/lib/error/overwriteModel.js +31 -0
- package/lib/error/parallelSave.js +33 -0
- package/lib/error/parallelValidate.js +33 -0
- package/lib/error/serverSelection.js +62 -0
- package/lib/error/setOptionError.js +103 -0
- package/lib/error/strict.js +35 -0
- package/lib/error/strictPopulate.js +31 -0
- package/lib/error/syncIndexes.js +30 -0
- package/lib/error/validation.js +97 -0
- package/lib/error/validator.js +100 -0
- package/lib/error/version.js +38 -0
- package/lib/helpers/aggregate/prepareDiscriminatorPipeline.js +39 -0
- package/lib/helpers/aggregate/stringifyFunctionOperators.js +50 -0
- package/lib/helpers/arrayDepth.js +33 -0
- package/lib/helpers/clone.js +204 -0
- package/lib/helpers/common.js +127 -0
- package/lib/helpers/createJSONSchemaTypeDefinition.js +24 -0
- package/lib/helpers/cursor/eachAsync.js +225 -0
- package/lib/helpers/discriminator/applyEmbeddedDiscriminators.js +36 -0
- package/lib/helpers/discriminator/areDiscriminatorValuesEqual.js +16 -0
- package/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js +12 -0
- package/lib/helpers/discriminator/getConstructor.js +29 -0
- package/lib/helpers/discriminator/getDiscriminatorByValue.js +28 -0
- package/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +27 -0
- package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +91 -0
- package/lib/helpers/document/applyDefaults.js +132 -0
- package/lib/helpers/document/applyTimestamps.js +106 -0
- package/lib/helpers/document/applyVirtuals.js +147 -0
- package/lib/helpers/document/cleanModifiedSubpaths.js +45 -0
- package/lib/helpers/document/compile.js +238 -0
- package/lib/helpers/document/getDeepestSubdocumentForPath.js +38 -0
- package/lib/helpers/document/getEmbeddedDiscriminatorPath.js +53 -0
- package/lib/helpers/document/handleSpreadDoc.js +35 -0
- package/lib/helpers/each.js +25 -0
- package/lib/helpers/error/combinePathErrors.js +22 -0
- package/lib/helpers/firstKey.js +8 -0
- package/lib/helpers/get.js +65 -0
- package/lib/helpers/getConstructorName.js +16 -0
- package/lib/helpers/getDefaultBulkwriteResult.js +18 -0
- package/lib/helpers/getFunctionName.js +10 -0
- package/lib/helpers/immediate.js +16 -0
- package/lib/helpers/indexes/applySchemaCollation.js +13 -0
- package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +14 -0
- package/lib/helpers/indexes/getRelatedIndexes.js +63 -0
- package/lib/helpers/indexes/isDefaultIdIndex.js +18 -0
- package/lib/helpers/indexes/isIndexEqual.js +95 -0
- package/lib/helpers/indexes/isIndexSpecEqual.js +32 -0
- package/lib/helpers/indexes/isTextIndex.js +16 -0
- package/lib/helpers/indexes/isTimeseriesIndex.js +16 -0
- package/lib/helpers/isAsyncFunction.js +9 -0
- package/lib/helpers/isBsonType.js +15 -0
- package/lib/helpers/isMongooseObject.js +22 -0
- package/lib/helpers/isObject.js +16 -0
- package/lib/helpers/isPOJO.js +12 -0
- package/lib/helpers/isPromise.js +6 -0
- package/lib/helpers/isSimpleValidator.js +22 -0
- package/lib/helpers/minimize.js +41 -0
- package/lib/helpers/model/applyDefaultsToPOJO.js +52 -0
- package/lib/helpers/model/applyHooks.js +140 -0
- package/lib/helpers/model/applyMethods.js +70 -0
- package/lib/helpers/model/applyStaticHooks.js +33 -0
- package/lib/helpers/model/applyStatics.js +13 -0
- package/lib/helpers/model/castBulkWrite.js +316 -0
- package/lib/helpers/model/decorateBulkWriteResult.js +8 -0
- package/lib/helpers/model/discriminator.js +265 -0
- package/lib/helpers/model/pushNestedArrayPaths.js +15 -0
- package/lib/helpers/omitUndefined.js +20 -0
- package/lib/helpers/once.js +12 -0
- package/lib/helpers/parallelLimit.js +37 -0
- package/lib/helpers/path/parentPaths.js +18 -0
- package/lib/helpers/path/setDottedPath.js +33 -0
- package/lib/helpers/pluralize.js +95 -0
- package/lib/helpers/populate/assignRawDocsToIdStructure.js +129 -0
- package/lib/helpers/populate/assignVals.js +360 -0
- package/lib/helpers/populate/createPopulateQueryFilter.js +97 -0
- package/lib/helpers/populate/getModelsMapForPopulate.js +776 -0
- package/lib/helpers/populate/getSchemaTypes.js +228 -0
- package/lib/helpers/populate/getVirtual.js +103 -0
- package/lib/helpers/populate/leanPopulateMap.js +7 -0
- package/lib/helpers/populate/lookupLocalFields.js +40 -0
- package/lib/helpers/populate/markArraySubdocsPopulated.js +49 -0
- package/lib/helpers/populate/modelNamesFromRefPath.js +66 -0
- package/lib/helpers/populate/removeDeselectedForeignField.js +31 -0
- package/lib/helpers/populate/setPopulatedVirtualValue.js +33 -0
- package/lib/helpers/populate/skipPopulateValue.js +10 -0
- package/lib/helpers/populate/validateRef.js +19 -0
- package/lib/helpers/printJestWarning.js +21 -0
- package/lib/helpers/processConnectionOptions.js +65 -0
- package/lib/helpers/projection/applyProjection.js +83 -0
- package/lib/helpers/projection/hasIncludedChildren.js +41 -0
- package/lib/helpers/projection/isDefiningProjection.js +18 -0
- package/lib/helpers/projection/isExclusive.js +37 -0
- package/lib/helpers/projection/isInclusive.js +39 -0
- package/lib/helpers/projection/isNestedProjection.js +8 -0
- package/lib/helpers/projection/isPathExcluded.js +40 -0
- package/lib/helpers/projection/isPathSelectedInclusive.js +28 -0
- package/lib/helpers/projection/isSubpath.js +14 -0
- package/lib/helpers/projection/parseProjection.js +33 -0
- package/lib/helpers/query/applyGlobalOption.js +29 -0
- package/lib/helpers/query/cast$expr.js +287 -0
- package/lib/helpers/query/castFilterPath.js +54 -0
- package/lib/helpers/query/castUpdate.js +643 -0
- package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +103 -0
- package/lib/helpers/query/handleImmutable.js +44 -0
- package/lib/helpers/query/handleReadPreferenceAliases.js +23 -0
- package/lib/helpers/query/hasDollarKeys.js +23 -0
- package/lib/helpers/query/isOperator.js +14 -0
- package/lib/helpers/query/sanitizeFilter.js +38 -0
- package/lib/helpers/query/sanitizeProjection.js +14 -0
- package/lib/helpers/query/selectPopulatedFields.js +62 -0
- package/lib/helpers/query/trusted.js +13 -0
- package/lib/helpers/query/validOps.js +3 -0
- package/lib/helpers/schema/addAutoId.js +7 -0
- package/lib/helpers/schema/applyBuiltinPlugins.js +12 -0
- package/lib/helpers/schema/applyPlugins.js +55 -0
- package/lib/helpers/schema/applyReadConcern.js +20 -0
- package/lib/helpers/schema/applyWriteConcern.js +39 -0
- package/lib/helpers/schema/cleanPositionalOperators.js +12 -0
- package/lib/helpers/schema/getIndexes.js +171 -0
- package/lib/helpers/schema/getKeysInSchemaOrder.js +28 -0
- package/lib/helpers/schema/getPath.js +43 -0
- package/lib/helpers/schema/getSubdocumentStrictValue.js +32 -0
- package/lib/helpers/schema/handleIdOption.js +20 -0
- package/lib/helpers/schema/handleTimestampOption.js +24 -0
- package/lib/helpers/schema/idGetter.js +34 -0
- package/lib/helpers/schema/merge.js +36 -0
- package/lib/helpers/schematype/handleImmutable.js +50 -0
- package/lib/helpers/setDefaultsOnInsert.js +158 -0
- package/lib/helpers/specialProperties.js +3 -0
- package/lib/helpers/symbols.js +20 -0
- package/lib/helpers/timers.js +3 -0
- package/lib/helpers/timestamps/setDocumentTimestamps.js +26 -0
- package/lib/helpers/timestamps/setupTimestamps.js +116 -0
- package/lib/helpers/topology/allServersUnknown.js +12 -0
- package/lib/helpers/topology/isAtlas.js +31 -0
- package/lib/helpers/topology/isSSLError.js +16 -0
- package/lib/helpers/update/applyTimestampsToChildren.js +193 -0
- package/lib/helpers/update/applyTimestampsToUpdate.js +131 -0
- package/lib/helpers/update/castArrayFilters.js +113 -0
- package/lib/helpers/update/decorateUpdateWithVersionKey.js +35 -0
- package/lib/helpers/update/modifiedPaths.js +33 -0
- package/lib/helpers/update/moveImmutableProperties.js +53 -0
- package/lib/helpers/update/removeUnusedArrayFilters.js +32 -0
- package/lib/helpers/update/updatedPathsByArrayFilter.js +27 -0
- package/lib/helpers/updateValidators.js +193 -0
- package/lib/index.js +17 -0
- package/lib/internal.js +46 -0
- package/lib/model.js +5010 -0
- package/lib/modifiedPathsSnapshot.js +9 -0
- package/lib/mongoose.js +1411 -0
- package/lib/options/populateOptions.js +36 -0
- package/lib/options/propertyOptions.js +8 -0
- package/lib/options/saveOptions.js +16 -0
- package/lib/options/schemaArrayOptions.js +78 -0
- package/lib/options/schemaBufferOptions.js +38 -0
- package/lib/options/schemaDateOptions.js +71 -0
- package/lib/options/schemaDocumentArrayOptions.js +68 -0
- package/lib/options/schemaMapOptions.js +43 -0
- package/lib/options/schemaNumberOptions.js +101 -0
- package/lib/options/schemaObjectIdOptions.js +64 -0
- package/lib/options/schemaStringOptions.js +138 -0
- package/lib/options/schemaSubdocumentOptions.js +66 -0
- package/lib/options/schemaTypeOptions.js +244 -0
- package/lib/options/schemaUnionOptions.js +32 -0
- package/lib/options/virtualOptions.js +164 -0
- package/lib/options.js +17 -0
- package/lib/plugins/index.js +6 -0
- package/lib/plugins/saveSubdocs.js +76 -0
- package/lib/plugins/sharding.js +84 -0
- package/lib/plugins/trackTransaction.js +84 -0
- package/lib/plugins/validateBeforeSave.js +41 -0
- package/lib/query.js +5673 -0
- package/lib/queryHelpers.js +387 -0
- package/lib/schema/array.js +699 -0
- package/lib/schema/bigint.js +282 -0
- package/lib/schema/boolean.js +332 -0
- package/lib/schema/buffer.js +343 -0
- package/lib/schema/date.js +467 -0
- package/lib/schema/decimal128.js +263 -0
- package/lib/schema/documentArray.js +656 -0
- package/lib/schema/documentArrayElement.js +137 -0
- package/lib/schema/double.js +246 -0
- package/lib/schema/index.js +32 -0
- package/lib/schema/int32.js +289 -0
- package/lib/schema/map.js +201 -0
- package/lib/schema/mixed.js +146 -0
- package/lib/schema/number.js +510 -0
- package/lib/schema/objectId.js +333 -0
- package/lib/schema/operators/bitwise.js +38 -0
- package/lib/schema/operators/exists.js +12 -0
- package/lib/schema/operators/geospatial.js +107 -0
- package/lib/schema/operators/helpers.js +32 -0
- package/lib/schema/operators/text.js +39 -0
- package/lib/schema/operators/type.js +20 -0
- package/lib/schema/string.js +733 -0
- package/lib/schema/subdocument.js +436 -0
- package/lib/schema/symbols.js +5 -0
- package/lib/schema/union.js +113 -0
- package/lib/schema/uuid.js +305 -0
- package/lib/schema.js +3226 -0
- package/lib/schemaType.js +1835 -0
- package/lib/stateMachine.js +232 -0
- package/lib/types/array/index.js +119 -0
- package/lib/types/array/isMongooseArray.js +5 -0
- package/lib/types/array/methods/index.js +1095 -0
- package/lib/types/arraySubdocument.js +207 -0
- package/lib/types/buffer.js +294 -0
- package/lib/types/decimal128.js +13 -0
- package/lib/types/documentArray/index.js +113 -0
- package/lib/types/documentArray/isMongooseDocumentArray.js +5 -0
- package/lib/types/documentArray/methods/index.js +415 -0
- package/lib/types/double.js +13 -0
- package/lib/types/index.js +23 -0
- package/lib/types/map.js +419 -0
- package/lib/types/objectid.js +41 -0
- package/lib/types/subdocument.js +464 -0
- package/lib/types/uuid.js +13 -0
- package/lib/utils.js +1054 -0
- package/lib/validOptions.js +42 -0
- package/lib/virtualType.js +204 -0
- package/package.json +148 -0
- package/types/aggregate.d.ts +180 -0
- package/types/augmentations.d.ts +9 -0
- package/types/callback.d.ts +8 -0
- package/types/collection.d.ts +49 -0
- package/types/connection.d.ts +297 -0
- package/types/cursor.d.ts +67 -0
- package/types/document.d.ts +374 -0
- package/types/error.d.ts +143 -0
- package/types/expressions.d.ts +3053 -0
- package/types/helpers.d.ts +32 -0
- package/types/index.d.ts +1056 -0
- package/types/indexes.d.ts +97 -0
- package/types/inferhydrateddoctype.d.ts +115 -0
- package/types/inferrawdoctype.d.ts +135 -0
- package/types/inferschematype.d.ts +337 -0
- package/types/middlewares.d.ts +59 -0
- package/types/models.d.ts +1306 -0
- package/types/mongooseoptions.d.ts +228 -0
- package/types/pipelinestage.d.ts +333 -0
- package/types/populate.d.ts +53 -0
- package/types/query.d.ts +934 -0
- package/types/schemaoptions.d.ts +282 -0
- package/types/schematypes.d.ts +654 -0
- package/types/session.d.ts +32 -0
- package/types/types.d.ts +109 -0
- package/types/utility.d.ts +175 -0
- package/types/validation.d.ts +39 -0
- package/types/virtuals.d.ts +14 -0
|
@@ -0,0 +1,1095 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Document = require('../../../document');
|
|
4
|
+
const ArraySubdocument = require('../../arraySubdocument');
|
|
5
|
+
const MongooseError = require('../../../error/mongooseError');
|
|
6
|
+
const cleanModifiedSubpaths = require('../../../helpers/document/cleanModifiedSubpaths');
|
|
7
|
+
const clone = require('../../../helpers/clone');
|
|
8
|
+
const internalToObjectOptions = require('../../../options').internalToObjectOptions;
|
|
9
|
+
const mpath = require('mpath');
|
|
10
|
+
const utils = require('../../../utils');
|
|
11
|
+
const isBsonType = require('../../../helpers/isBsonType');
|
|
12
|
+
|
|
13
|
+
const arrayAtomicsBackupSymbol = require('../../../helpers/symbols').arrayAtomicsBackupSymbol;
|
|
14
|
+
const arrayAtomicsSymbol = require('../../../helpers/symbols').arrayAtomicsSymbol;
|
|
15
|
+
const arrayParentSymbol = require('../../../helpers/symbols').arrayParentSymbol;
|
|
16
|
+
const arrayPathSymbol = require('../../../helpers/symbols').arrayPathSymbol;
|
|
17
|
+
const arraySchemaSymbol = require('../../../helpers/symbols').arraySchemaSymbol;
|
|
18
|
+
const populateModelSymbol = require('../../../helpers/symbols').populateModelSymbol;
|
|
19
|
+
const slicedSymbol = Symbol('mongoose#Array#sliced');
|
|
20
|
+
|
|
21
|
+
const _basePush = Array.prototype.push;
|
|
22
|
+
|
|
23
|
+
/*!
|
|
24
|
+
* ignore
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const methods = {
|
|
28
|
+
/**
|
|
29
|
+
* Depopulates stored atomic operation values as necessary for direct insertion to MongoDB.
|
|
30
|
+
*
|
|
31
|
+
* If no atomics exist, we return all array values after conversion.
|
|
32
|
+
*
|
|
33
|
+
* @return {Array}
|
|
34
|
+
* @method $__getAtomics
|
|
35
|
+
* @memberOf MongooseArray
|
|
36
|
+
* @instance
|
|
37
|
+
* @api private
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
$__getAtomics() {
|
|
41
|
+
const ret = [];
|
|
42
|
+
const keys = Object.keys(this[arrayAtomicsSymbol] || {});
|
|
43
|
+
let i = keys.length;
|
|
44
|
+
|
|
45
|
+
const opts = Object.assign({}, internalToObjectOptions, { _isNested: true });
|
|
46
|
+
|
|
47
|
+
if (i === 0) {
|
|
48
|
+
ret[0] = ['$set', this.toObject(opts)];
|
|
49
|
+
return ret;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
while (i--) {
|
|
53
|
+
const op = keys[i];
|
|
54
|
+
let val = this[arrayAtomicsSymbol][op];
|
|
55
|
+
|
|
56
|
+
// the atomic values which are arrays are not MongooseArrays. we
|
|
57
|
+
// need to convert their elements as if they were MongooseArrays
|
|
58
|
+
// to handle populated arrays versus DocumentArrays properly.
|
|
59
|
+
if (utils.isMongooseObject(val)) {
|
|
60
|
+
val = val.toObject(opts);
|
|
61
|
+
} else if (Array.isArray(val)) {
|
|
62
|
+
val = this.toObject.call(val, opts);
|
|
63
|
+
} else if (Array.isArray(val?.$each)) {
|
|
64
|
+
val.$each = this.toObject.call(val.$each, opts);
|
|
65
|
+
} else if (typeof val?.valueOf === 'function') {
|
|
66
|
+
val = val.valueOf();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (op === '$addToSet') {
|
|
70
|
+
val = { $each: val };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
ret.push([op, val]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return ret;
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Public API for getting atomics. Alias for $__getAtomics() that can be
|
|
81
|
+
* implemented by custom container types.
|
|
82
|
+
*
|
|
83
|
+
* @return {Array}
|
|
84
|
+
* @method getAtomics
|
|
85
|
+
* @memberOf MongooseArray
|
|
86
|
+
* @instance
|
|
87
|
+
* @api public
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
getAtomics() {
|
|
91
|
+
return this.$__getAtomics();
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Clears all pending atomic operations. Called by Mongoose after save().
|
|
96
|
+
*
|
|
97
|
+
* @return {void}
|
|
98
|
+
* @method clearAtomics
|
|
99
|
+
* @memberOf MongooseArray
|
|
100
|
+
* @instance
|
|
101
|
+
* @api public
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
clearAtomics() {
|
|
105
|
+
this[arrayAtomicsBackupSymbol] = this[arrayAtomicsSymbol];
|
|
106
|
+
this[arrayAtomicsSymbol] = {};
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/*!
|
|
110
|
+
* ignore
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
$atomics() {
|
|
114
|
+
return this[arrayAtomicsSymbol];
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
/*!
|
|
118
|
+
* ignore
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
$parent() {
|
|
122
|
+
return this[arrayParentSymbol];
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/*!
|
|
126
|
+
* ignore
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
$path() {
|
|
130
|
+
return this[arrayPathSymbol];
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
/*!
|
|
134
|
+
* ignore
|
|
135
|
+
*/
|
|
136
|
+
$schemaType() {
|
|
137
|
+
return this[arraySchemaSymbol];
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Atomically shifts the array at most one time per document `save()`.
|
|
142
|
+
*
|
|
143
|
+
* #### Note:
|
|
144
|
+
*
|
|
145
|
+
* _Calling this multiple times on an array before saving sends the same command as calling it once._
|
|
146
|
+
* _This update is implemented using the MongoDB [$pop](https://www.mongodb.com/docs/manual/reference/operator/update/pop/) method which enforces this restriction._
|
|
147
|
+
*
|
|
148
|
+
* doc.array = [1,2,3];
|
|
149
|
+
*
|
|
150
|
+
* const shifted = doc.array.$shift();
|
|
151
|
+
* console.log(shifted); // 1
|
|
152
|
+
* console.log(doc.array); // [2,3]
|
|
153
|
+
*
|
|
154
|
+
* // no affect
|
|
155
|
+
* shifted = doc.array.$shift();
|
|
156
|
+
* console.log(doc.array); // [2,3]
|
|
157
|
+
*
|
|
158
|
+
* doc.save(function (err) {
|
|
159
|
+
* if (err) return handleError(err);
|
|
160
|
+
*
|
|
161
|
+
* // we saved, now $shift works again
|
|
162
|
+
* shifted = doc.array.$shift();
|
|
163
|
+
* console.log(shifted ); // 2
|
|
164
|
+
* console.log(doc.array); // [3]
|
|
165
|
+
* })
|
|
166
|
+
*
|
|
167
|
+
* @api public
|
|
168
|
+
* @memberOf MongooseArray
|
|
169
|
+
* @instance
|
|
170
|
+
* @method $shift
|
|
171
|
+
* @see mongodb https://www.mongodb.com/docs/manual/reference/operator/update/pop/
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
$shift() {
|
|
175
|
+
this._registerAtomic('$pop', -1);
|
|
176
|
+
this._markModified();
|
|
177
|
+
|
|
178
|
+
// only allow shifting once
|
|
179
|
+
const __array = this.__array;
|
|
180
|
+
if (__array._shifted) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
__array._shifted = true;
|
|
184
|
+
|
|
185
|
+
return [].shift.call(__array);
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Pops the array atomically at most one time per document `save()`.
|
|
190
|
+
*
|
|
191
|
+
* #### NOTE:
|
|
192
|
+
*
|
|
193
|
+
* _Calling this multiple times on an array before saving sends the same command as calling it once._
|
|
194
|
+
* _This update is implemented using the MongoDB [$pop](https://www.mongodb.com/docs/manual/reference/operator/update/pop/) method which enforces this restriction._
|
|
195
|
+
*
|
|
196
|
+
* doc.array = [1,2,3];
|
|
197
|
+
*
|
|
198
|
+
* const popped = doc.array.$pop();
|
|
199
|
+
* console.log(popped); // 3
|
|
200
|
+
* console.log(doc.array); // [1,2]
|
|
201
|
+
*
|
|
202
|
+
* // no affect
|
|
203
|
+
* popped = doc.array.$pop();
|
|
204
|
+
* console.log(doc.array); // [1,2]
|
|
205
|
+
*
|
|
206
|
+
* doc.save(function (err) {
|
|
207
|
+
* if (err) return handleError(err);
|
|
208
|
+
*
|
|
209
|
+
* // we saved, now $pop works again
|
|
210
|
+
* popped = doc.array.$pop();
|
|
211
|
+
* console.log(popped); // 2
|
|
212
|
+
* console.log(doc.array); // [1]
|
|
213
|
+
* })
|
|
214
|
+
*
|
|
215
|
+
* @api public
|
|
216
|
+
* @method $pop
|
|
217
|
+
* @memberOf MongooseArray
|
|
218
|
+
* @instance
|
|
219
|
+
* @see mongodb https://www.mongodb.com/docs/manual/reference/operator/update/pop/
|
|
220
|
+
* @method $pop
|
|
221
|
+
* @memberOf MongooseArray
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
$pop() {
|
|
225
|
+
this._registerAtomic('$pop', 1);
|
|
226
|
+
this._markModified();
|
|
227
|
+
|
|
228
|
+
// only allow popping once
|
|
229
|
+
if (this._popped) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this._popped = true;
|
|
233
|
+
|
|
234
|
+
return [].pop.call(this);
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
/*!
|
|
238
|
+
* ignore
|
|
239
|
+
*/
|
|
240
|
+
|
|
241
|
+
$schema() {
|
|
242
|
+
return this[arraySchemaSymbol];
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Casts a member based on this arrays schema.
|
|
247
|
+
*
|
|
248
|
+
* @param {any} value
|
|
249
|
+
* @return value the casted value
|
|
250
|
+
* @method _cast
|
|
251
|
+
* @api private
|
|
252
|
+
* @memberOf MongooseArray
|
|
253
|
+
*/
|
|
254
|
+
|
|
255
|
+
_cast(value) {
|
|
256
|
+
let populated = false;
|
|
257
|
+
let Model;
|
|
258
|
+
|
|
259
|
+
const parent = this[arrayParentSymbol];
|
|
260
|
+
if (parent) {
|
|
261
|
+
populated = parent.$populated(this[arrayPathSymbol], true);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (populated && value != null) {
|
|
265
|
+
// cast to the populated Models schema
|
|
266
|
+
Model = populated.options[populateModelSymbol];
|
|
267
|
+
if (Model == null) {
|
|
268
|
+
throw new MongooseError('No populated model found for path `' + this[arrayPathSymbol] + '`. This is likely a bug in Mongoose, please report an issue on github.com/Automattic/mongoose.');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// only objects are permitted so we can safely assume that
|
|
272
|
+
// non-objects are to be interpreted as _id
|
|
273
|
+
if (Buffer.isBuffer(value) ||
|
|
274
|
+
isBsonType(value, 'ObjectId') || !utils.isObject(value)) {
|
|
275
|
+
value = { _id: value };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// gh-2399
|
|
279
|
+
// we should cast model only when it's not a discriminator
|
|
280
|
+
const isDisc = value.schema?.discriminatorMapping?.key !== undefined;
|
|
281
|
+
if (!isDisc) {
|
|
282
|
+
value = new Model(value);
|
|
283
|
+
}
|
|
284
|
+
return this[arraySchemaSymbol].embeddedSchemaType.applySetters(value, parent, true);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return this[arraySchemaSymbol].embeddedSchemaType.applySetters(value, parent, false);
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Internal helper for .map()
|
|
292
|
+
*
|
|
293
|
+
* @api private
|
|
294
|
+
* @return {Number}
|
|
295
|
+
* @method _mapCast
|
|
296
|
+
* @memberOf MongooseArray
|
|
297
|
+
*/
|
|
298
|
+
|
|
299
|
+
_mapCast(val, index) {
|
|
300
|
+
return this._cast(val, this.length + index);
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Marks this array as modified.
|
|
305
|
+
*
|
|
306
|
+
* If it bubbles up from an embedded document change, then it takes the following arguments (otherwise, takes 0 arguments)
|
|
307
|
+
*
|
|
308
|
+
* @param {ArraySubdocument} subdoc the embedded doc that invoked this method on the Array
|
|
309
|
+
* @param {String} embeddedPath the path which changed in the subdoc
|
|
310
|
+
* @method _markModified
|
|
311
|
+
* @api private
|
|
312
|
+
* @memberOf MongooseArray
|
|
313
|
+
*/
|
|
314
|
+
|
|
315
|
+
_markModified(elem) {
|
|
316
|
+
const parent = this[arrayParentSymbol];
|
|
317
|
+
let dirtyPath;
|
|
318
|
+
|
|
319
|
+
if (parent) {
|
|
320
|
+
dirtyPath = this[arrayPathSymbol];
|
|
321
|
+
|
|
322
|
+
if (arguments.length) {
|
|
323
|
+
dirtyPath = dirtyPath + '.' + elem;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (dirtyPath != null && dirtyPath.endsWith('.$')) {
|
|
327
|
+
return this;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
parent.markModified(dirtyPath, arguments.length !== 0 ? elem : parent);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return this;
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Register an atomic operation with the parent.
|
|
338
|
+
*
|
|
339
|
+
* @param {Array} op operation
|
|
340
|
+
* @param {any} val
|
|
341
|
+
* @method _registerAtomic
|
|
342
|
+
* @api private
|
|
343
|
+
* @memberOf MongooseArray
|
|
344
|
+
*/
|
|
345
|
+
|
|
346
|
+
_registerAtomic(op, val) {
|
|
347
|
+
if (this[slicedSymbol]) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (op === '$set') {
|
|
351
|
+
// $set takes precedence over all other ops.
|
|
352
|
+
// mark entire array modified.
|
|
353
|
+
this[arrayAtomicsSymbol] = { $set: val };
|
|
354
|
+
cleanModifiedSubpaths(this[arrayParentSymbol], this[arrayPathSymbol]);
|
|
355
|
+
this._markModified();
|
|
356
|
+
return this;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const atomics = this[arrayAtomicsSymbol];
|
|
360
|
+
|
|
361
|
+
// reset pop/shift after save
|
|
362
|
+
if (op === '$pop' && !('$pop' in atomics)) {
|
|
363
|
+
const _this = this;
|
|
364
|
+
this[arrayParentSymbol].once('save', function() {
|
|
365
|
+
_this._popped = _this._shifted = null;
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// check for impossible $atomic combos (Mongo denies more than one
|
|
370
|
+
// $atomic op on a single path
|
|
371
|
+
if (atomics.$set || utils.hasOwnKeys(atomics) && !(op in atomics)) {
|
|
372
|
+
// a different op was previously registered.
|
|
373
|
+
// save the entire thing.
|
|
374
|
+
this[arrayAtomicsSymbol] = { $set: this };
|
|
375
|
+
return this;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
let selector;
|
|
379
|
+
|
|
380
|
+
if (op === '$pullAll' || op === '$addToSet') {
|
|
381
|
+
atomics[op] || (atomics[op] = []);
|
|
382
|
+
atomics[op] = atomics[op].concat(val);
|
|
383
|
+
} else if (op === '$pullDocs') {
|
|
384
|
+
const pullOp = atomics['$pull'] || (atomics['$pull'] = {});
|
|
385
|
+
if (val[0] instanceof ArraySubdocument) {
|
|
386
|
+
selector = pullOp['$or'] || (pullOp['$or'] = []);
|
|
387
|
+
Array.prototype.push.apply(selector, val.map(v => {
|
|
388
|
+
return v.toObject({
|
|
389
|
+
transform: (doc, ret) => {
|
|
390
|
+
if (v == null || v.$__ == null) {
|
|
391
|
+
return ret;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
Object.keys(v.$__.activePaths.getStatePaths('default')).forEach(path => {
|
|
395
|
+
mpath.unset(path, ret);
|
|
396
|
+
|
|
397
|
+
_minimizePath(ret, path);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
return ret;
|
|
401
|
+
},
|
|
402
|
+
virtuals: false
|
|
403
|
+
});
|
|
404
|
+
}));
|
|
405
|
+
} else {
|
|
406
|
+
selector = pullOp['_id'] || (pullOp['_id'] = { $in: [] });
|
|
407
|
+
selector['$in'] = selector['$in'].concat(val);
|
|
408
|
+
}
|
|
409
|
+
} else if (op === '$push') {
|
|
410
|
+
atomics.$push = atomics.$push || { $each: [] };
|
|
411
|
+
if (val != null && utils.hasUserDefinedProperty(val, '$each')) {
|
|
412
|
+
atomics.$push = val;
|
|
413
|
+
} else {
|
|
414
|
+
if (val.length === 1) {
|
|
415
|
+
atomics.$push.$each.push(val[0]);
|
|
416
|
+
} else if (val.length < 10000) {
|
|
417
|
+
atomics.$push.$each.push(...val);
|
|
418
|
+
} else {
|
|
419
|
+
for (const v of val) {
|
|
420
|
+
atomics.$push.$each.push(v);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
atomics[op] = val;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return this;
|
|
429
|
+
},
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Adds values to the array if not already present.
|
|
433
|
+
*
|
|
434
|
+
* #### Example:
|
|
435
|
+
*
|
|
436
|
+
* console.log(doc.array) // [2,3,4]
|
|
437
|
+
* const added = doc.array.addToSet(4,5);
|
|
438
|
+
* console.log(doc.array) // [2,3,4,5]
|
|
439
|
+
* console.log(added) // [5]
|
|
440
|
+
*
|
|
441
|
+
* @param {...any} [args]
|
|
442
|
+
* @return {Array} the values that were added
|
|
443
|
+
* @memberOf MongooseArray
|
|
444
|
+
* @api public
|
|
445
|
+
* @method addToSet
|
|
446
|
+
*/
|
|
447
|
+
|
|
448
|
+
addToSet() {
|
|
449
|
+
_checkManualPopulation(this, arguments);
|
|
450
|
+
_depopulateIfNecessary(this, arguments);
|
|
451
|
+
|
|
452
|
+
const values = [].map.call(arguments, this._mapCast, this);
|
|
453
|
+
const added = [];
|
|
454
|
+
let type = '';
|
|
455
|
+
if (values[0] instanceof ArraySubdocument) {
|
|
456
|
+
type = 'doc';
|
|
457
|
+
} else if (values[0] instanceof Date) {
|
|
458
|
+
type = 'date';
|
|
459
|
+
} else if (isBsonType(values[0], 'ObjectId')) {
|
|
460
|
+
type = 'ObjectId';
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const rawValues = utils.isMongooseArray(values) ? values.__array : values;
|
|
464
|
+
const rawArray = utils.isMongooseArray(this) ? this.__array : this;
|
|
465
|
+
|
|
466
|
+
rawValues.forEach(function(v) {
|
|
467
|
+
let found;
|
|
468
|
+
const val = +v;
|
|
469
|
+
switch (type) {
|
|
470
|
+
case 'doc':
|
|
471
|
+
found = this.some(function(doc) {
|
|
472
|
+
return doc.equals(v);
|
|
473
|
+
});
|
|
474
|
+
break;
|
|
475
|
+
case 'date':
|
|
476
|
+
found = this.some(function(d) {
|
|
477
|
+
return +d === val;
|
|
478
|
+
});
|
|
479
|
+
break;
|
|
480
|
+
case 'ObjectId':
|
|
481
|
+
found = this.find(o => o.toString() === v.toString());
|
|
482
|
+
break;
|
|
483
|
+
default:
|
|
484
|
+
found = ~this.indexOf(v);
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (!found) {
|
|
489
|
+
this._markModified();
|
|
490
|
+
rawArray.push(v);
|
|
491
|
+
this._registerAtomic('$addToSet', v);
|
|
492
|
+
[].push.call(added, v);
|
|
493
|
+
}
|
|
494
|
+
}, this);
|
|
495
|
+
|
|
496
|
+
return added;
|
|
497
|
+
},
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Returns the number of pending atomic operations to send to the db for this array.
|
|
501
|
+
*
|
|
502
|
+
* @api private
|
|
503
|
+
* @return {Number}
|
|
504
|
+
* @method hasAtomics
|
|
505
|
+
* @memberOf MongooseArray
|
|
506
|
+
*/
|
|
507
|
+
|
|
508
|
+
hasAtomics() {
|
|
509
|
+
if (!utils.isPOJO(this[arrayAtomicsSymbol])) {
|
|
510
|
+
return 0;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return Object.keys(this[arrayAtomicsSymbol]).length;
|
|
514
|
+
},
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Return whether or not the `obj` is included in the array.
|
|
518
|
+
*
|
|
519
|
+
* @param {Object} obj the item to check
|
|
520
|
+
* @param {Number} fromIndex
|
|
521
|
+
* @return {Boolean}
|
|
522
|
+
* @api public
|
|
523
|
+
* @method includes
|
|
524
|
+
* @memberOf MongooseArray
|
|
525
|
+
*/
|
|
526
|
+
|
|
527
|
+
includes(obj, fromIndex) {
|
|
528
|
+
const ret = this.indexOf(obj, fromIndex);
|
|
529
|
+
return ret !== -1;
|
|
530
|
+
},
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Return the index of `obj` or `-1` if not found.
|
|
534
|
+
*
|
|
535
|
+
* @param {Object} obj the item to look for
|
|
536
|
+
* @param {Number} fromIndex
|
|
537
|
+
* @return {Number}
|
|
538
|
+
* @api public
|
|
539
|
+
* @method indexOf
|
|
540
|
+
* @memberOf MongooseArray
|
|
541
|
+
*/
|
|
542
|
+
|
|
543
|
+
indexOf(obj, fromIndex) {
|
|
544
|
+
if (isBsonType(obj, 'ObjectId')) {
|
|
545
|
+
obj = obj.toString();
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
fromIndex = fromIndex == null ? 0 : fromIndex;
|
|
549
|
+
const len = this.length;
|
|
550
|
+
for (let i = fromIndex; i < len; ++i) {
|
|
551
|
+
if (obj == this[i]) {
|
|
552
|
+
return i;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return -1;
|
|
556
|
+
},
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Helper for console.log
|
|
560
|
+
*
|
|
561
|
+
* @api public
|
|
562
|
+
* @method inspect
|
|
563
|
+
* @memberOf MongooseArray
|
|
564
|
+
*/
|
|
565
|
+
|
|
566
|
+
inspect() {
|
|
567
|
+
return JSON.stringify(this);
|
|
568
|
+
},
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Pushes items to the array non-atomically.
|
|
572
|
+
*
|
|
573
|
+
* #### Note:
|
|
574
|
+
*
|
|
575
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
|
|
576
|
+
*
|
|
577
|
+
* @param {...any} [args]
|
|
578
|
+
* @api public
|
|
579
|
+
* @method nonAtomicPush
|
|
580
|
+
* @memberOf MongooseArray
|
|
581
|
+
*/
|
|
582
|
+
|
|
583
|
+
nonAtomicPush() {
|
|
584
|
+
const values = [].map.call(arguments, this._mapCast, this);
|
|
585
|
+
this._markModified();
|
|
586
|
+
const ret = [].push.apply(this, values);
|
|
587
|
+
this._registerAtomic('$set', this);
|
|
588
|
+
return ret;
|
|
589
|
+
},
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Wraps [`Array#pop`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/pop) with proper change tracking.
|
|
593
|
+
*
|
|
594
|
+
* #### Note:
|
|
595
|
+
*
|
|
596
|
+
* _marks the entire array as modified which will pass the entire thing to $set potentially overwriting any changes that happen between when you retrieved the object and when you save it._
|
|
597
|
+
*
|
|
598
|
+
* @see MongooseArray#$pop https://mongoosejs.com/docs/api/array.html#MongooseArray.prototype.$pop()
|
|
599
|
+
* @api public
|
|
600
|
+
* @method pop
|
|
601
|
+
* @memberOf MongooseArray
|
|
602
|
+
*/
|
|
603
|
+
|
|
604
|
+
pop() {
|
|
605
|
+
this._markModified();
|
|
606
|
+
const ret = [].pop.call(this);
|
|
607
|
+
this._registerAtomic('$set', this);
|
|
608
|
+
return ret;
|
|
609
|
+
},
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Pulls items from the array atomically. Equality is determined by casting
|
|
613
|
+
* the provided value to an embedded document and comparing using
|
|
614
|
+
* [the `Document.equals()` function.](https://mongoosejs.com/docs/api/document.html#Document.prototype.equals())
|
|
615
|
+
*
|
|
616
|
+
* #### Example:
|
|
617
|
+
*
|
|
618
|
+
* doc.array.pull(ObjectId)
|
|
619
|
+
* doc.array.pull({ _id: 'someId' })
|
|
620
|
+
* doc.array.pull(36)
|
|
621
|
+
* doc.array.pull('tag 1', 'tag 2')
|
|
622
|
+
*
|
|
623
|
+
* To remove a document from a subdocument array we may pass an object with a matching `_id`.
|
|
624
|
+
*
|
|
625
|
+
* doc.subdocs.push({ _id: 4815162342 })
|
|
626
|
+
* doc.subdocs.pull({ _id: 4815162342 }) // removed
|
|
627
|
+
*
|
|
628
|
+
* Or we may passing the _id directly and let mongoose take care of it.
|
|
629
|
+
*
|
|
630
|
+
* doc.subdocs.push({ _id: 4815162342 })
|
|
631
|
+
* doc.subdocs.pull(4815162342); // works
|
|
632
|
+
*
|
|
633
|
+
* The first pull call will result in a atomic operation on the database, if pull is called repeatedly without saving the document, a $set operation is used on the complete array instead, overwriting possible changes that happened on the database in the meantime.
|
|
634
|
+
*
|
|
635
|
+
* @param {...any} [args]
|
|
636
|
+
* @see mongodb https://www.mongodb.com/docs/manual/reference/operator/update/pull/
|
|
637
|
+
* @api public
|
|
638
|
+
* @method pull
|
|
639
|
+
* @memberOf MongooseArray
|
|
640
|
+
*/
|
|
641
|
+
|
|
642
|
+
pull() {
|
|
643
|
+
const values = [].map.call(arguments, (v, i) => this._cast(v, i, { defaults: false }), this);
|
|
644
|
+
let cur = this;
|
|
645
|
+
if (utils.isMongooseArray(cur)) {
|
|
646
|
+
cur = cur.__array;
|
|
647
|
+
}
|
|
648
|
+
let i = cur.length;
|
|
649
|
+
let mem;
|
|
650
|
+
this._markModified();
|
|
651
|
+
|
|
652
|
+
while (i--) {
|
|
653
|
+
mem = cur[i];
|
|
654
|
+
if (mem instanceof Document) {
|
|
655
|
+
const some = values.some(function(v) {
|
|
656
|
+
return mem.equals(v);
|
|
657
|
+
});
|
|
658
|
+
if (some) {
|
|
659
|
+
cur.splice(i, 1);
|
|
660
|
+
}
|
|
661
|
+
} else if (~this.indexOf.call(values, mem)) {
|
|
662
|
+
cur.splice(i, 1);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (values[0] instanceof ArraySubdocument) {
|
|
667
|
+
this._registerAtomic('$pullDocs', values.map(function(v) {
|
|
668
|
+
const _id = v.$__getValue('_id');
|
|
669
|
+
if (_id === undefined || v.$isDefault('_id')) {
|
|
670
|
+
return v;
|
|
671
|
+
}
|
|
672
|
+
return _id;
|
|
673
|
+
}));
|
|
674
|
+
} else {
|
|
675
|
+
this._registerAtomic('$pullAll', values);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
// Might have modified child paths and then pulled, like
|
|
680
|
+
// `doc.children[1].name = 'test';` followed by
|
|
681
|
+
// `doc.children.remove(doc.children[0]);`. In this case we fall back
|
|
682
|
+
// to a `$set` on the whole array. See #3511
|
|
683
|
+
if (cleanModifiedSubpaths(this[arrayParentSymbol], this[arrayPathSymbol]) > 0) {
|
|
684
|
+
this._registerAtomic('$set', this);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return this;
|
|
688
|
+
},
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
|
|
692
|
+
*
|
|
693
|
+
* #### Example:
|
|
694
|
+
*
|
|
695
|
+
* const schema = Schema({ nums: [Number] });
|
|
696
|
+
* const Model = mongoose.model('Test', schema);
|
|
697
|
+
*
|
|
698
|
+
* const doc = await Model.create({ nums: [3, 4] });
|
|
699
|
+
* doc.nums.push(5); // Add 5 to the end of the array
|
|
700
|
+
* await doc.save();
|
|
701
|
+
*
|
|
702
|
+
* // You can also pass an object with `$each` as the
|
|
703
|
+
* // first parameter to use MongoDB's `$position`
|
|
704
|
+
* doc.nums.push({
|
|
705
|
+
* $each: [1, 2],
|
|
706
|
+
* $position: 0
|
|
707
|
+
* });
|
|
708
|
+
* doc.nums; // [1, 2, 3, 4, 5]
|
|
709
|
+
*
|
|
710
|
+
* @param {...Object} [args]
|
|
711
|
+
* @api public
|
|
712
|
+
* @method push
|
|
713
|
+
* @memberOf MongooseArray
|
|
714
|
+
*/
|
|
715
|
+
|
|
716
|
+
push() {
|
|
717
|
+
let values = arguments;
|
|
718
|
+
let atomic = values;
|
|
719
|
+
const isOverwrite = values[0] != null &&
|
|
720
|
+
utils.hasUserDefinedProperty(values[0], '$each');
|
|
721
|
+
const arr = utils.isMongooseArray(this) ? this.__array : this;
|
|
722
|
+
if (isOverwrite) {
|
|
723
|
+
atomic = values[0];
|
|
724
|
+
values = values[0].$each;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
if (this[arraySchemaSymbol] == null) {
|
|
728
|
+
return _basePush.apply(this, values);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
_checkManualPopulation(this, values);
|
|
732
|
+
_depopulateIfNecessary(this, values);
|
|
733
|
+
|
|
734
|
+
values = [].map.call(values, this._mapCast, this);
|
|
735
|
+
let ret;
|
|
736
|
+
const atomics = this[arrayAtomicsSymbol];
|
|
737
|
+
this._markModified();
|
|
738
|
+
if (isOverwrite) {
|
|
739
|
+
atomic.$each = values;
|
|
740
|
+
|
|
741
|
+
if ((atomics.$push && atomics.$push.$each && atomics.$push.$each.length || 0) !== 0 &&
|
|
742
|
+
atomics.$push.$position != atomic.$position) {
|
|
743
|
+
if (atomic.$position != null) {
|
|
744
|
+
[].splice.apply(arr, [atomic.$position, 0].concat(values));
|
|
745
|
+
ret = arr.length;
|
|
746
|
+
} else {
|
|
747
|
+
ret = [].push.apply(arr, values);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
this._registerAtomic('$set', this);
|
|
751
|
+
} else if (atomic.$position != null) {
|
|
752
|
+
[].splice.apply(arr, [atomic.$position, 0].concat(values));
|
|
753
|
+
ret = this.length;
|
|
754
|
+
} else {
|
|
755
|
+
ret = [].push.apply(arr, values);
|
|
756
|
+
}
|
|
757
|
+
} else {
|
|
758
|
+
atomic = values;
|
|
759
|
+
ret = _basePush.apply(arr, values);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
this._registerAtomic('$push', atomic);
|
|
763
|
+
|
|
764
|
+
return ret;
|
|
765
|
+
},
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Alias of [pull](https://mongoosejs.com/docs/api/array.html#MongooseArray.prototype.pull())
|
|
769
|
+
*
|
|
770
|
+
* @see MongooseArray#pull https://mongoosejs.com/docs/api/array.html#MongooseArray.prototype.pull()
|
|
771
|
+
* @see mongodb https://www.mongodb.com/docs/manual/reference/operator/update/pull/
|
|
772
|
+
* @api public
|
|
773
|
+
* @memberOf MongooseArray
|
|
774
|
+
* @instance
|
|
775
|
+
* @method remove
|
|
776
|
+
*/
|
|
777
|
+
|
|
778
|
+
remove() {
|
|
779
|
+
return this.pull.apply(this, arguments);
|
|
780
|
+
},
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Sets the casted `val` at index `i` and marks the array modified.
|
|
784
|
+
*
|
|
785
|
+
* #### Example:
|
|
786
|
+
*
|
|
787
|
+
* // given documents based on the following
|
|
788
|
+
* const Doc = mongoose.model('Doc', new Schema({ array: [Number] }));
|
|
789
|
+
*
|
|
790
|
+
* const doc = new Doc({ array: [2,3,4] })
|
|
791
|
+
*
|
|
792
|
+
* console.log(doc.array) // [2,3,4]
|
|
793
|
+
*
|
|
794
|
+
* doc.array.set(1,"5");
|
|
795
|
+
* console.log(doc.array); // [2,5,4] // properly cast to number
|
|
796
|
+
* doc.save() // the change is saved
|
|
797
|
+
*
|
|
798
|
+
* // VS not using array#set
|
|
799
|
+
* doc.array[1] = "5";
|
|
800
|
+
* console.log(doc.array); // [2,"5",4] // no casting
|
|
801
|
+
* doc.save() // change is not saved
|
|
802
|
+
*
|
|
803
|
+
* @return {Array} this
|
|
804
|
+
* @api public
|
|
805
|
+
* @method set
|
|
806
|
+
* @memberOf MongooseArray
|
|
807
|
+
*/
|
|
808
|
+
|
|
809
|
+
set(i, val, skipModified) {
|
|
810
|
+
const arr = this.__array;
|
|
811
|
+
if (skipModified) {
|
|
812
|
+
arr[i] = val;
|
|
813
|
+
return this;
|
|
814
|
+
}
|
|
815
|
+
const value = methods._cast.call(this, val, i);
|
|
816
|
+
methods._markModified.call(this, i);
|
|
817
|
+
arr[i] = value;
|
|
818
|
+
return this;
|
|
819
|
+
},
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Wraps [`Array#shift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.
|
|
823
|
+
*
|
|
824
|
+
* #### Example:
|
|
825
|
+
*
|
|
826
|
+
* doc.array = [2,3];
|
|
827
|
+
* const res = doc.array.shift();
|
|
828
|
+
* console.log(res) // 2
|
|
829
|
+
* console.log(doc.array) // [3]
|
|
830
|
+
*
|
|
831
|
+
* #### Note:
|
|
832
|
+
*
|
|
833
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
|
|
834
|
+
*
|
|
835
|
+
* @api public
|
|
836
|
+
* @method shift
|
|
837
|
+
* @memberOf MongooseArray
|
|
838
|
+
*/
|
|
839
|
+
|
|
840
|
+
shift() {
|
|
841
|
+
const arr = utils.isMongooseArray(this) ? this.__array : this;
|
|
842
|
+
this._markModified();
|
|
843
|
+
const ret = [].shift.call(arr);
|
|
844
|
+
this._registerAtomic('$set', this);
|
|
845
|
+
return ret;
|
|
846
|
+
},
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Wraps [`Array#sort`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) with proper change tracking.
|
|
850
|
+
*
|
|
851
|
+
* #### Note:
|
|
852
|
+
*
|
|
853
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
|
|
854
|
+
*
|
|
855
|
+
* @api public
|
|
856
|
+
* @method sort
|
|
857
|
+
* @memberOf MongooseArray
|
|
858
|
+
* @see MasteringJS: Array sort https://masteringjs.io/tutorials/fundamentals/array-sort
|
|
859
|
+
*/
|
|
860
|
+
|
|
861
|
+
sort() {
|
|
862
|
+
const arr = utils.isMongooseArray(this) ? this.__array : this;
|
|
863
|
+
const ret = [].sort.apply(arr, arguments);
|
|
864
|
+
this._registerAtomic('$set', this);
|
|
865
|
+
return ret;
|
|
866
|
+
},
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Wraps [`Array#splice`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting.
|
|
870
|
+
*
|
|
871
|
+
* #### Note:
|
|
872
|
+
*
|
|
873
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
|
|
874
|
+
*
|
|
875
|
+
* @api public
|
|
876
|
+
* @method splice
|
|
877
|
+
* @memberOf MongooseArray
|
|
878
|
+
* @see MasteringJS: Array splice https://masteringjs.io/tutorials/fundamentals/array-splice
|
|
879
|
+
*/
|
|
880
|
+
|
|
881
|
+
splice() {
|
|
882
|
+
let ret;
|
|
883
|
+
const arr = utils.isMongooseArray(this) ? this.__array : this;
|
|
884
|
+
|
|
885
|
+
this._markModified();
|
|
886
|
+
_checkManualPopulation(this, Array.prototype.slice.call(arguments, 2));
|
|
887
|
+
|
|
888
|
+
if (arguments.length) {
|
|
889
|
+
let vals;
|
|
890
|
+
if (this[arraySchemaSymbol] == null) {
|
|
891
|
+
vals = arguments;
|
|
892
|
+
} else {
|
|
893
|
+
vals = [];
|
|
894
|
+
for (let i = 0; i < arguments.length; ++i) {
|
|
895
|
+
vals[i] = i < 2 ?
|
|
896
|
+
arguments[i] :
|
|
897
|
+
this._cast(arguments[i], arguments[0] + (i - 2));
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
ret = [].splice.apply(arr, vals);
|
|
902
|
+
this._registerAtomic('$set', this);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
return ret;
|
|
906
|
+
},
|
|
907
|
+
|
|
908
|
+
/*!
|
|
909
|
+
* ignore
|
|
910
|
+
*/
|
|
911
|
+
|
|
912
|
+
toBSON() {
|
|
913
|
+
return this.toObject(internalToObjectOptions);
|
|
914
|
+
},
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Returns a native js Array.
|
|
918
|
+
*
|
|
919
|
+
* @param {Object} options
|
|
920
|
+
* @return {Array}
|
|
921
|
+
* @api public
|
|
922
|
+
* @method toObject
|
|
923
|
+
* @memberOf MongooseArray
|
|
924
|
+
*/
|
|
925
|
+
|
|
926
|
+
toObject(options) {
|
|
927
|
+
const arr = utils.isMongooseArray(this) ? this.__array : this;
|
|
928
|
+
if (options?.depopulate) {
|
|
929
|
+
options = clone(options);
|
|
930
|
+
options._isNested = true;
|
|
931
|
+
// Ensure return value is a vanilla array, because in Node.js 6+ `map()`
|
|
932
|
+
// is smart enough to use the inherited array's constructor.
|
|
933
|
+
return [].concat(arr).map(function(doc) {
|
|
934
|
+
return doc instanceof Document
|
|
935
|
+
? doc.toObject(options)
|
|
936
|
+
: doc;
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
return [].concat(arr);
|
|
941
|
+
},
|
|
942
|
+
|
|
943
|
+
$toObject() {
|
|
944
|
+
return this.constructor.prototype.toObject.apply(this, arguments);
|
|
945
|
+
},
|
|
946
|
+
/**
|
|
947
|
+
* Wraps [`Array#unshift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.
|
|
948
|
+
*
|
|
949
|
+
* #### Note:
|
|
950
|
+
*
|
|
951
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
|
|
952
|
+
*
|
|
953
|
+
* @api public
|
|
954
|
+
* @method unshift
|
|
955
|
+
* @memberOf MongooseArray
|
|
956
|
+
*/
|
|
957
|
+
|
|
958
|
+
unshift() {
|
|
959
|
+
_checkManualPopulation(this, arguments);
|
|
960
|
+
|
|
961
|
+
let values;
|
|
962
|
+
if (this[arraySchemaSymbol] == null) {
|
|
963
|
+
values = arguments;
|
|
964
|
+
} else {
|
|
965
|
+
values = [].map.call(arguments, this._cast, this);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
const arr = utils.isMongooseArray(this) ? this.__array : this;
|
|
969
|
+
this._markModified();
|
|
970
|
+
[].unshift.apply(arr, values);
|
|
971
|
+
this._registerAtomic('$set', this);
|
|
972
|
+
return this.length;
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
|
|
976
|
+
/*!
|
|
977
|
+
* ignore
|
|
978
|
+
*/
|
|
979
|
+
|
|
980
|
+
function _isAllSubdocs(docs, ref) {
|
|
981
|
+
if (!ref) {
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
for (const arg of docs) {
|
|
986
|
+
if (arg == null) {
|
|
987
|
+
return false;
|
|
988
|
+
}
|
|
989
|
+
const model = arg.constructor;
|
|
990
|
+
if (!(arg instanceof Document) ||
|
|
991
|
+
(model.modelName !== ref && model.baseModelName !== ref)) {
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
return true;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/*!
|
|
1000
|
+
* Minimize _just_ empty objects along the path chain specified
|
|
1001
|
+
* by `parts`, ignoring all other paths. Useful in cases where
|
|
1002
|
+
* you want to minimize after unsetting a path.
|
|
1003
|
+
*
|
|
1004
|
+
* #### Example:
|
|
1005
|
+
*
|
|
1006
|
+
* const obj = { foo: { bar: { baz: {} } }, a: {} };
|
|
1007
|
+
* _minimizePath(obj, 'foo.bar.baz');
|
|
1008
|
+
* obj; // { a: {} }
|
|
1009
|
+
*/
|
|
1010
|
+
|
|
1011
|
+
function _minimizePath(obj, parts, i) {
|
|
1012
|
+
if (typeof parts === 'string') {
|
|
1013
|
+
if (parts.indexOf('.') === -1) {
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
parts = mpath.stringToParts(parts);
|
|
1018
|
+
}
|
|
1019
|
+
i = i || 0;
|
|
1020
|
+
if (i >= parts.length) {
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
if (obj == null || typeof obj !== 'object') {
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
_minimizePath(obj[parts[0]], parts, i + 1);
|
|
1028
|
+
if (obj[parts[0]] != null && typeof obj[parts[0]] === 'object' && utils.hasOwnKeys(obj[parts[0]]) === false) {
|
|
1029
|
+
delete obj[parts[0]];
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/*!
|
|
1034
|
+
* ignore
|
|
1035
|
+
*/
|
|
1036
|
+
|
|
1037
|
+
function _checkManualPopulation(arr, docs) {
|
|
1038
|
+
const ref = arr == null ?
|
|
1039
|
+
null :
|
|
1040
|
+
arr[arraySchemaSymbol]?.embeddedSchemaType?.options?.ref || null;
|
|
1041
|
+
if (arr.length === 0 &&
|
|
1042
|
+
docs.length !== 0) {
|
|
1043
|
+
if (_isAllSubdocs(docs, ref)) {
|
|
1044
|
+
arr[arrayParentSymbol].$populated(arr[arrayPathSymbol], [], {
|
|
1045
|
+
[populateModelSymbol]: docs[0].constructor
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/*!
|
|
1052
|
+
* If `docs` isn't all instances of the right model, depopulate `arr`
|
|
1053
|
+
*/
|
|
1054
|
+
|
|
1055
|
+
function _depopulateIfNecessary(arr, docs) {
|
|
1056
|
+
const ref = arr == null ?
|
|
1057
|
+
null :
|
|
1058
|
+
arr[arraySchemaSymbol]?.embeddedSchemaType?.options?.ref || null;
|
|
1059
|
+
const parentDoc = arr[arrayParentSymbol];
|
|
1060
|
+
const path = arr[arrayPathSymbol];
|
|
1061
|
+
if (!ref || !parentDoc.populated(path)) {
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
for (const doc of docs) {
|
|
1065
|
+
if (doc == null) {
|
|
1066
|
+
continue;
|
|
1067
|
+
}
|
|
1068
|
+
if (typeof doc !== 'object' || doc instanceof String || doc instanceof Number || doc instanceof Buffer || utils.isMongooseType(doc)) {
|
|
1069
|
+
parentDoc.depopulate(path);
|
|
1070
|
+
break;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
const returnVanillaArrayMethods = [
|
|
1076
|
+
'filter',
|
|
1077
|
+
'flat',
|
|
1078
|
+
'flatMap',
|
|
1079
|
+
'map',
|
|
1080
|
+
'slice'
|
|
1081
|
+
];
|
|
1082
|
+
for (const method of returnVanillaArrayMethods) {
|
|
1083
|
+
if (Array.prototype[method] == null) {
|
|
1084
|
+
continue;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
methods[method] = function() {
|
|
1088
|
+
const _arr = utils.isMongooseArray(this) ? this.__array : this;
|
|
1089
|
+
const arr = [].concat(_arr);
|
|
1090
|
+
|
|
1091
|
+
return arr[method].apply(arr, arguments);
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
module.exports = methods;
|