mongoose 6.7.2 → 6.7.4

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/lib/cast.js CHANGED
@@ -264,7 +264,7 @@ module.exports = function cast(schema, obj, options, context) {
264
264
  }
265
265
 
266
266
  const strict = 'strict' in options ? options.strict : schema.options.strict;
267
- const strictQuery = getStrictQuery(options, schema._userProvidedOptions, schema.options);
267
+ const strictQuery = getStrictQuery(options, schema._userProvidedOptions, schema.options, context);
268
268
  if (options.upsert && strict) {
269
269
  if (strict === 'throw') {
270
270
  throw new StrictModeError(path);
@@ -374,7 +374,7 @@ function _cast(val, numbertype, context) {
374
374
  }
375
375
  }
376
376
 
377
- function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions) {
377
+ function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions, context) {
378
378
  if ('strictQuery' in queryOptions) {
379
379
  return queryOptions.strictQuery;
380
380
  }
@@ -387,5 +387,17 @@ function getStrictQuery(queryOptions, schemaUserProvidedOptions, schemaOptions)
387
387
  if ('strict' in schemaUserProvidedOptions) {
388
388
  return schemaUserProvidedOptions.strict;
389
389
  }
390
+ const mongooseOptions = context.mongooseCollection &&
391
+ context.mongooseCollection.conn &&
392
+ context.mongooseCollection.conn.base &&
393
+ context.mongooseCollection.conn.base.options;
394
+ if (mongooseOptions) {
395
+ if ('strictQuery' in mongooseOptions) {
396
+ return mongooseOptions.strictQuery;
397
+ }
398
+ if ('strict' in mongooseOptions) {
399
+ return mongooseOptions.strict;
400
+ }
401
+ }
390
402
  return schemaOptions.strictQuery;
391
403
  }
package/lib/document.js CHANGED
@@ -220,6 +220,17 @@ function Document(obj, fields, skipId, options) {
220
220
  * const user = await User.findOne({ name: 'John Smith' });
221
221
  * user.$isNew; // false
222
222
  *
223
+ * Mongoose sets `$isNew` to `false` immediately after `save()` succeeds.
224
+ * That means Mongoose sets `$isNew` to false **before** `post('save')` hooks run.
225
+ * In `post('save')` hooks, `$isNew` will be `false` if `save()` succeeded.
226
+ *
227
+ * #### Example:
228
+ *
229
+ * userSchema.post('save', function() {
230
+ * this.$isNew; // false
231
+ * });
232
+ * await User.create({ name: 'John Smith' });
233
+ *
223
234
  * For subdocuments, `$isNew` is true if either the parent has `$isNew` set,
224
235
  * or if you create a new subdocument.
225
236
  *
@@ -1468,13 +1479,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1468
1479
  const doc = this.$isSubdocument ? this.ownerDocument() : this;
1469
1480
  savedState = doc.$__.savedState;
1470
1481
  savedStatePath = this.$isSubdocument ? this.$__.fullPath + '.' + path : path;
1471
- if (savedState != null) {
1472
- const firstDot = savedStatePath.indexOf('.');
1473
- const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
1474
- if (!savedState.hasOwnProperty(topLevelPath)) {
1475
- savedState[topLevelPath] = utils.clone(doc.$__getValue(topLevelPath));
1476
- }
1477
- }
1482
+ doc.$__saveInitialState(savedStatePath);
1478
1483
  }
1479
1484
 
1480
1485
  this.$__set(pathToMark, path, options, constructing, parts, schema, val, priorVal);
@@ -1583,6 +1588,10 @@ Document.prototype.$__shouldModify = function(pathToMark, path, options, constru
1583
1588
  if (this.$isNew) {
1584
1589
  return true;
1585
1590
  }
1591
+ // Is path already modified? If so, always modify. We may unmark modified later.
1592
+ if (path in this.$__.activePaths.getStatePaths('modify')) {
1593
+ return true;
1594
+ }
1586
1595
 
1587
1596
  // Re: the note about gh-7196, `val` is the raw value without casting or
1588
1597
  // setters if the full path is under a single nested subdoc because we don't
@@ -1780,11 +1789,10 @@ Document.prototype.$inc = function $inc(path, val) {
1780
1789
 
1781
1790
  const currentValue = this.$__getValue(path) || 0;
1782
1791
 
1783
- this.$__setValue(path, currentValue + val);
1784
-
1785
1792
  this.$__.primitiveAtomics = this.$__.primitiveAtomics || {};
1786
1793
  this.$__.primitiveAtomics[path] = { $inc: val };
1787
1794
  this.markModified(path);
1795
+ this.$__setValue(path, currentValue + val);
1788
1796
 
1789
1797
  return this;
1790
1798
  };
@@ -1927,6 +1935,8 @@ Document.prototype.$__path = function(path) {
1927
1935
  */
1928
1936
 
1929
1937
  Document.prototype.markModified = function(path, scope) {
1938
+ this.$__saveInitialState(path);
1939
+
1930
1940
  this.$__.activePaths.modify(path);
1931
1941
  if (scope != null && !this.$isSubdocument) {
1932
1942
  this.$__.pathsToScopes = this.$__pathsToScopes || {};
@@ -1934,6 +1944,22 @@ Document.prototype.markModified = function(path, scope) {
1934
1944
  }
1935
1945
  };
1936
1946
 
1947
+ /*!
1948
+ * ignore
1949
+ */
1950
+
1951
+ Document.prototype.$__saveInitialState = function $__saveInitialState(path) {
1952
+ const savedState = this.$__.savedState;
1953
+ const savedStatePath = path;
1954
+ if (savedState != null) {
1955
+ const firstDot = savedStatePath.indexOf('.');
1956
+ const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
1957
+ if (!savedState.hasOwnProperty(topLevelPath)) {
1958
+ savedState[topLevelPath] = utils.clone(this.$__getValue(topLevelPath));
1959
+ }
1960
+ }
1961
+ };
1962
+
1937
1963
  /**
1938
1964
  * Clears the modified state on the specified path.
1939
1965
  *
@@ -3379,6 +3405,7 @@ Document.prototype.$__dirty = function() {
3379
3405
  schema: _this.$__path(path)
3380
3406
  };
3381
3407
  });
3408
+
3382
3409
  // gh-2558: if we had to set a default and the value is not undefined,
3383
3410
  // we have to save as well
3384
3411
  all = all.concat(this.$__.activePaths.map('default', function(path) {
@@ -7,6 +7,8 @@
7
7
  const Binary = require('../driver').get().Binary;
8
8
  const isBsonType = require('./isBsonType');
9
9
  const isMongooseObject = require('./isMongooseObject');
10
+ const MongooseError = require('../error');
11
+ const util = require('util');
10
12
 
11
13
  exports.flatten = flatten;
12
14
  exports.modifiedPaths = modifiedPaths;
@@ -67,7 +69,25 @@ function flatten(update, path, options, schema) {
67
69
  * ignore
68
70
  */
69
71
 
70
- function modifiedPaths(update, path, result) {
72
+ function modifiedPaths(update, path, result, recursion = null) {
73
+ if (update == null || typeof update !== 'object') {
74
+ return;
75
+ }
76
+
77
+ if (recursion == null) {
78
+ recursion = {
79
+ raw: { update, path },
80
+ trace: new WeakSet()
81
+ };
82
+ }
83
+
84
+ if (recursion.trace.has(update)) {
85
+ throw new MongooseError(`a circular reference in the update value, updateValue:
86
+ ${util.inspect(recursion.raw.update, { showHidden: false, depth: 1 })}
87
+ updatePath: '${recursion.raw.path}'`);
88
+ }
89
+ recursion.trace.add(update);
90
+
71
91
  const keys = Object.keys(update || {});
72
92
  const numKeys = keys.length;
73
93
  result = result || {};
@@ -83,7 +103,7 @@ function modifiedPaths(update, path, result) {
83
103
  val = val.toObject({ transform: false, virtuals: false });
84
104
  }
85
105
  if (shouldFlatten(val)) {
86
- modifiedPaths(val, path + key, result);
106
+ modifiedPaths(val, path + key, result, recursion);
87
107
  }
88
108
  }
89
109
 
@@ -96,11 +116,11 @@ function modifiedPaths(update, path, result) {
96
116
 
97
117
  function shouldFlatten(val) {
98
118
  return val &&
99
- typeof val === 'object' &&
100
- !(val instanceof Date) &&
101
- !isBsonType(val, 'ObjectID') &&
102
- (!Array.isArray(val) || val.length !== 0) &&
103
- !(val instanceof Buffer) &&
104
- !isBsonType(val, 'Decimal128') &&
105
- !(val instanceof Binary);
119
+ typeof val === 'object' &&
120
+ !(val instanceof Date) &&
121
+ !isBsonType(val, 'ObjectID') &&
122
+ (!Array.isArray(val) || val.length !== 0) &&
123
+ !(val instanceof Buffer) &&
124
+ !isBsonType(val, 'Decimal128') &&
125
+ !(val instanceof Binary);
106
126
  }
@@ -33,7 +33,7 @@ module.exports = function eachAsync(next, fn, options, callback) {
33
33
  const aggregatedErrors = [];
34
34
  const enqueue = asyncQueue();
35
35
 
36
- let drained = false;
36
+ let aborted = false;
37
37
 
38
38
  return promiseOrCallback(callback, cb => {
39
39
  if (signal != null) {
@@ -42,7 +42,7 @@ module.exports = function eachAsync(next, fn, options, callback) {
42
42
  }
43
43
 
44
44
  signal.addEventListener('abort', () => {
45
- drained = true;
45
+ aborted = true;
46
46
  return cb(null);
47
47
  }, { once: true });
48
48
  }
@@ -63,90 +63,104 @@ module.exports = function eachAsync(next, fn, options, callback) {
63
63
  function iterate(finalCallback) {
64
64
  let handleResultsInProgress = 0;
65
65
  let currentDocumentIndex = 0;
66
- let documentsBatch = [];
67
66
 
68
67
  let error = null;
69
68
  for (let i = 0; i < parallel; ++i) {
70
- enqueue(fetch);
69
+ enqueue(createFetch());
71
70
  }
72
71
 
73
- function fetch(done) {
74
- if (drained || error) {
75
- return done();
76
- }
72
+ function createFetch() {
73
+ let documentsBatch = [];
74
+ let drained = false;
75
+
76
+ return fetch;
77
77
 
78
- next(function(err, doc) {
79
- if (drained || error != null) {
78
+ function fetch(done) {
79
+ if (drained || aborted) {
80
+ return done();
81
+ } else if (error) {
80
82
  return done();
81
83
  }
82
- if (err != null) {
83
- if (continueOnError) {
84
- aggregatedErrors.push(err);
85
- } else {
86
- error = err;
87
- finalCallback(err);
84
+
85
+ next(function(err, doc) {
86
+ if (error != null) {
88
87
  return done();
89
88
  }
90
- }
91
- if (doc == null) {
92
- drained = true;
93
- if (handleResultsInProgress <= 0) {
94
- const finalErr = continueOnError ?
95
- createEachAsyncMultiError(aggregatedErrors) :
96
- error;
97
-
98
- finalCallback(finalErr);
99
- } else if (batchSize && documentsBatch.length) {
100
- handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack);
89
+ if (err != null) {
90
+ if (err.name === 'MongoCursorExhaustedError') {
91
+ // We may end up calling `next()` multiple times on an exhausted
92
+ // cursor, which leads to an error. In case cursor is exhausted,
93
+ // just treat it as if the cursor returned no document, which is
94
+ // how a cursor indicates it is exhausted.
95
+ doc = null;
96
+ } else if (continueOnError) {
97
+ aggregatedErrors.push(err);
98
+ } else {
99
+ error = err;
100
+ finalCallback(err);
101
+ return done();
102
+ }
103
+ }
104
+ if (doc == null) {
105
+ drained = true;
106
+ if (handleResultsInProgress <= 0) {
107
+ const finalErr = continueOnError ?
108
+ createEachAsyncMultiError(aggregatedErrors) :
109
+ error;
110
+
111
+ finalCallback(finalErr);
112
+ } else if (batchSize && documentsBatch.length) {
113
+ handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack);
114
+ }
115
+ return done();
101
116
  }
102
- return done();
103
- }
104
117
 
105
- ++handleResultsInProgress;
118
+ ++handleResultsInProgress;
106
119
 
107
- // Kick off the subsequent `next()` before handling the result, but
108
- // make sure we know that we still have a result to handle re: #8422
109
- immediate(() => done());
120
+ // Kick off the subsequent `next()` before handling the result, but
121
+ // make sure we know that we still have a result to handle re: #8422
122
+ immediate(() => done());
110
123
 
111
- if (batchSize) {
112
- documentsBatch.push(doc);
113
- }
124
+ if (batchSize) {
125
+ documentsBatch.push(doc);
126
+ }
114
127
 
115
- // If the current documents size is less than the provided patch size don't process the documents yet
116
- if (batchSize && documentsBatch.length !== batchSize) {
117
- immediate(() => enqueue(fetch));
118
- return;
119
- }
128
+ // If the current documents size is less than the provided batch size don't process the documents yet
129
+ if (batchSize && documentsBatch.length !== batchSize) {
130
+ immediate(() => enqueue(fetch));
131
+ return;
132
+ }
120
133
 
121
- const docsToProcess = batchSize ? documentsBatch : doc;
134
+ const docsToProcess = batchSize ? documentsBatch : doc;
122
135
 
123
- function handleNextResultCallBack(err) {
124
- if (batchSize) {
125
- handleResultsInProgress -= documentsBatch.length;
126
- documentsBatch = [];
127
- } else {
128
- --handleResultsInProgress;
129
- }
130
- if (err != null) {
131
- if (continueOnError) {
132
- aggregatedErrors.push(err);
136
+ function handleNextResultCallBack(err) {
137
+ if (batchSize) {
138
+ handleResultsInProgress -= documentsBatch.length;
139
+ documentsBatch = [];
133
140
  } else {
134
- error = err;
135
- return finalCallback(err);
141
+ --handleResultsInProgress;
142
+ }
143
+ if (err != null) {
144
+ if (continueOnError) {
145
+ aggregatedErrors.push(err);
146
+ } else {
147
+ error = err;
148
+ return finalCallback(err);
149
+ }
150
+ }
151
+ if ((drained || aborted) && handleResultsInProgress <= 0) {
152
+ const finalErr = continueOnError ?
153
+ createEachAsyncMultiError(aggregatedErrors) :
154
+ error;
155
+ return finalCallback(finalErr);
136
156
  }
137
- }
138
- if (drained && handleResultsInProgress <= 0) {
139
- const finalErr = continueOnError ?
140
- createEachAsyncMultiError(aggregatedErrors) :
141
- error;
142
- return finalCallback(finalErr);
143
- }
144
157
 
145
- immediate(() => enqueue(fetch));
146
- }
158
+ immediate(() => enqueue(fetch));
159
+ }
147
160
 
148
- handleNextResult(docsToProcess, currentDocumentIndex++, handleNextResultCallBack);
149
- });
161
+ handleNextResult(docsToProcess, currentDocumentIndex++, handleNextResultCallBack);
162
+ });
163
+ }
150
164
  }
151
165
  }
152
166
 
@@ -28,7 +28,7 @@ module.exports = function setupTimestamps(schema, timestamps) {
28
28
  schema.$timestamps = { createdAt: createdAt, updatedAt: updatedAt };
29
29
 
30
30
  if (createdAt && !schema.paths[createdAt]) {
31
- const baseImmutableCreatedAt = schema.base.get('timestamps.createdAt.immutable');
31
+ const baseImmutableCreatedAt = schema.base != null ? schema.base.get('timestamps.createdAt.immutable') : null;
32
32
  const immutable = baseImmutableCreatedAt != null ? baseImmutableCreatedAt : true;
33
33
  schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable };
34
34
  }
package/lib/index.js CHANGED
@@ -205,7 +205,6 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
205
205
  * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
206
206
  * - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
207
207
  * - 'cloneSchemas': `false` by default. Set to `true` to `clone()` all schemas before compiling into a model.
208
- * - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
209
208
  * - 'timestamps.createdAt.immutable': `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable) which means you can update the `createdAt`
210
209
  * - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
211
210
  * - 'objectIdGetter': `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
package/lib/model.js CHANGED
@@ -4556,7 +4556,7 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) {
4556
4556
  * - match: optional query conditions to match
4557
4557
  * - model: optional name of the model to use for population
4558
4558
  * - options: optional query options like sort, limit, etc
4559
- * - justOne: optional boolean, if true Mongoose will always set `path` to an array. Inferred from schema by default.
4559
+ * - justOne: optional boolean, if true Mongoose will always set `path` to a document, or `null` if no document was found. If false, Mongoose will always set `path` to an array, which will be empty if no documents are found. Inferred from schema by default.
4560
4560
  * - strictPopulate: optional boolean, set to `false` to allow populating paths that aren't in the schema.
4561
4561
  *
4562
4562
  * #### Example:
package/lib/query.js CHANGED
@@ -4574,8 +4574,11 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) {
4574
4574
  * #### Example:
4575
4575
  *
4576
4576
  * const res = await Person.updateOne({ name: 'Jean-Luc Picard' }, { ship: 'USS Enterprise' });
4577
- * res.n; // Number of documents matched
4578
- * res.nModified; // Number of documents modified
4577
+ * res.acknowledged; // Indicates if this write result was acknowledged. If not, then all other members of this result will be undefined.
4578
+ * res.matchedCount; // Number of documents that matched the filter
4579
+ * res.modifiedCount; // Number of documents that were modified
4580
+ * res.upsertedCount; // Number of documents that were upserted
4581
+ * res.upsertedId; // Identifier of the inserted document (if an upsert took place)
4579
4582
  *
4580
4583
  * This function triggers the following middleware.
4581
4584
  *
@@ -4638,8 +4641,11 @@ Query.prototype.updateOne = function(conditions, doc, options, callback) {
4638
4641
  * #### Example:
4639
4642
  *
4640
4643
  * const res = await Person.replaceOne({ _id: 24601 }, { name: 'Jean Valjean' });
4641
- * res.n; // Number of documents matched
4642
- * res.nModified; // Number of documents modified
4644
+ * res.acknowledged; // Indicates if this write result was acknowledged. If not, then all other members of this result will be undefined.
4645
+ * res.matchedCount; // Number of documents that matched the filter
4646
+ * res.modifiedCount; // Number of documents that were modified
4647
+ * res.upsertedCount; // Number of documents that were upserted
4648
+ * res.upsertedId; // Identifier of the inserted document (if an upsert took place)
4643
4649
  *
4644
4650
  * This function triggers the following middleware.
4645
4651
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "6.7.2",
4
+ "version": "6.7.4",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -190,9 +190,6 @@ declare module 'mongoose' {
190
190
  /** Returns the list of paths that have been modified. */
191
191
  modifiedPaths(options?: { includeChildren?: boolean }): Array<string>;
192
192
 
193
- /** The name of the model */
194
- modelName: string;
195
-
196
193
  /**
197
194
  * Overwrite all values in this document with the values of `obj`, except
198
195
  * for immutable properties. Behaves similarly to `set()`, except for it
package/types/index.d.ts CHANGED
@@ -78,7 +78,13 @@ declare module 'mongoose' {
78
78
  schema?: TSchema,
79
79
  collection?: string,
80
80
  options?: CompileModelOptions
81
- ): Model<InferSchemaType<TSchema>, ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>, ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>, {}, TSchema> & ObtainSchemaGeneric<TSchema, 'TStaticMethods'>;
81
+ ): Model<
82
+ InferSchemaType<TSchema>,
83
+ ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
84
+ ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>,
85
+ ObtainSchemaGeneric<TSchema, 'TVirtuals'>,
86
+ TSchema
87
+ > & ObtainSchemaGeneric<TSchema, 'TStaticMethods'>;
82
88
 
83
89
  export function model<T>(name: string, schema?: Schema<T, any, any> | Schema<T & Document, any, any>, collection?: string, options?: CompileModelOptions): Model<T>;
84
90
 
@@ -161,29 +161,30 @@ type PathEnumOrString<T extends SchemaTypeOptions<string>['enum']> = T extends (
161
161
  type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueType> = {}, TypeKey extends TypeKeyBaseType = DefaultTypeKey> =
162
162
  PathValueType extends Schema ? InferSchemaType<PathValueType> :
163
163
  PathValueType extends (infer Item)[] ? IfEquals<Item, never, any[], Item extends Schema ? Types.DocumentArray<ObtainDocumentPathType<Item, TypeKey>> : ObtainDocumentPathType<Item, TypeKey>[]> :
164
- PathValueType extends StringSchemaDefinition ? PathEnumOrString<Options['enum']> :
165
- IfEquals<PathValueType, Schema.Types.String> extends true ? PathEnumOrString<Options['enum']> :
166
- IfEquals<PathValueType, String> extends true ? PathEnumOrString<Options['enum']> :
167
- PathValueType extends NumberSchemaDefinition ? Options['enum'] extends ReadonlyArray<any> ? Options['enum'][number] : number :
168
- IfEquals<PathValueType, Schema.Types.Number> extends true ? number :
169
- PathValueType extends DateSchemaDefinition ? Date :
170
- IfEquals<PathValueType, Schema.Types.Date> extends true ? Date :
171
- PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer :
172
- PathValueType extends BooleanSchemaDefinition ? boolean :
173
- IfEquals<PathValueType, Schema.Types.Boolean> extends true ? boolean :
174
- PathValueType extends ObjectIdSchemaDefinition ? Types.ObjectId :
175
- IfEquals<PathValueType, Types.ObjectId> extends true ? Types.ObjectId :
176
- IfEquals<PathValueType, Schema.Types.ObjectId> extends true ? Types.ObjectId :
177
- PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 :
178
- IfEquals<PathValueType, Schema.Types.Decimal128> extends true ? Types.Decimal128 :
179
- IfEquals<PathValueType, Types.Decimal128> extends true ? Types.Decimal128 :
180
- PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer :
181
- IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
182
- PathValueType extends MapConstructor ? Map<string, ResolvePathType<Options['of']>> :
183
- PathValueType extends ArrayConstructor ? any[] :
184
- PathValueType extends typeof Schema.Types.Mixed ? any:
185
- IfEquals<PathValueType, ObjectConstructor> extends true ? any:
186
- IfEquals<PathValueType, {}> extends true ? any:
187
- PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
188
- PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, TypeKey> :
189
- unknown;
164
+ PathValueType extends ReadonlyArray<infer Item> ? IfEquals<Item, never, any[], Item extends Schema ? Types.DocumentArray<ObtainDocumentPathType<Item, TypeKey>> : ObtainDocumentPathType<Item, TypeKey>[]> :
165
+ PathValueType extends StringSchemaDefinition ? PathEnumOrString<Options['enum']> :
166
+ IfEquals<PathValueType, Schema.Types.String> extends true ? PathEnumOrString<Options['enum']> :
167
+ IfEquals<PathValueType, String> extends true ? PathEnumOrString<Options['enum']> :
168
+ PathValueType extends NumberSchemaDefinition ? Options['enum'] extends ReadonlyArray<any> ? Options['enum'][number] : number :
169
+ IfEquals<PathValueType, Schema.Types.Number> extends true ? number :
170
+ PathValueType extends DateSchemaDefinition ? Date :
171
+ IfEquals<PathValueType, Schema.Types.Date> extends true ? Date :
172
+ PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer :
173
+ PathValueType extends BooleanSchemaDefinition ? boolean :
174
+ IfEquals<PathValueType, Schema.Types.Boolean> extends true ? boolean :
175
+ PathValueType extends ObjectIdSchemaDefinition ? Types.ObjectId :
176
+ IfEquals<PathValueType, Types.ObjectId> extends true ? Types.ObjectId :
177
+ IfEquals<PathValueType, Schema.Types.ObjectId> extends true ? Types.ObjectId :
178
+ PathValueType extends 'decimal128' | 'Decimal128' | typeof Schema.Types.Decimal128 ? Types.Decimal128 :
179
+ IfEquals<PathValueType, Schema.Types.Decimal128> extends true ? Types.Decimal128 :
180
+ IfEquals<PathValueType, Types.Decimal128> extends true ? Types.Decimal128 :
181
+ PathValueType extends 'uuid' | 'UUID' | typeof Schema.Types.UUID ? Buffer :
182
+ IfEquals<PathValueType, Schema.Types.UUID> extends true ? Buffer :
183
+ PathValueType extends MapConstructor ? Map<string, ResolvePathType<Options['of']>> :
184
+ PathValueType extends ArrayConstructor ? any[] :
185
+ PathValueType extends typeof Schema.Types.Mixed ? any:
186
+ IfEquals<PathValueType, ObjectConstructor> extends true ? any:
187
+ IfEquals<PathValueType, {}> extends true ? any:
188
+ PathValueType extends typeof SchemaType ? PathValueType['prototype'] :
189
+ PathValueType extends Record<string, any> ? ObtainDocumentType<PathValueType, any, TypeKey> :
190
+ unknown;
@@ -213,7 +213,7 @@ declare module 'mongoose' {
213
213
 
214
214
  export interface ReplaceWith {
215
215
  /** [`$replaceWith` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/replaceWith/) */
216
- $replaceWith: ObjectExpressionOperator | { [field: string]: Expression };
216
+ $replaceWith: ObjectExpressionOperator | { [field: string]: Expression } | `$${string}`;
217
217
  }
218
218
 
219
219
  export interface Sample {
@@ -26,8 +26,9 @@ declare module 'mongoose' {
26
26
  /** deep populate */
27
27
  populate?: string | PopulateOptions | (string | PopulateOptions)[];
28
28
  /**
29
- * If true Mongoose will always set `path` to an array, if false Mongoose will
30
- * always set `path` to a document. Inferred from schema by default.
29
+ * If true Mongoose will always set `path` to a document, or `null` if no document was found.
30
+ * If false Mongoose will always set `path` to an array, which will be empty if no documents are found.
31
+ * Inferred from schema by default.
31
32
  */
32
33
  justOne?: boolean;
33
34
  /** transform function to call on every populated doc */
package/types/query.d.ts CHANGED
@@ -616,7 +616,7 @@ declare module 'mongoose' {
616
616
  then: Promise<ResultType>['then'];
617
617
 
618
618
  /** Converts this query to a customized, reusable query constructor with all arguments and options retained. */
619
- toConstructor(): typeof Query<ResultType, DocType, THelpers, RawDocType>;
619
+ toConstructor<RetType = typeof Query>(): RetType;
620
620
 
621
621
  /** Declare and/or execute this query as an update() operation. */
622
622
  update(filter?: FilterQuery<DocType>, update?: UpdateQuery<DocType> | UpdateWithAggregationPipeline, options?: QueryOptions<DocType> | null, callback?: Callback<UpdateWriteOpResult>): QueryWithHelpers<UpdateWriteOpResult, DocType, THelpers, RawDocType>;
Binary file