mongoose 6.1.2 → 6.1.6

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/index.d.ts CHANGED
@@ -77,6 +77,10 @@ declare module 'mongoose' {
77
77
  export function syncIndexes(options?: Record<string, unknown>): Promise<Array<string>>;
78
78
  export function syncIndexes(options: Record<string, unknown> | null, callback: Callback<Array<string>>): void;
79
79
 
80
+ /* Tells `sanitizeFilter()` to skip the given object when filtering out potential query selector injection attacks.
81
+ * Use this method when you have a known query selector that you want to use. */
82
+ export function trusted<T>(obj: T): T;
83
+
80
84
  /** The Mongoose module's default connection. Equivalent to `mongoose.connections[0]`, see [`connections`](#mongoose_Mongoose-connections). */
81
85
  export const connection: Connection;
82
86
 
@@ -763,7 +767,7 @@ declare module 'mongoose' {
763
767
 
764
768
  export const Model: Model<any>;
765
769
  interface Model<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> extends NodeJS.EventEmitter, AcceptsDiscriminator {
766
- new(doc?: AnyKeys<T> & AnyObject, fields?: any | null, options?: boolean | AnyObject): HydratedDocument<T, TMethods, TVirtuals>;
770
+ new<DocType = AnyKeys<T> & AnyObject>(doc?: DocType, fields?: any | null, options?: boolean | AnyObject): HydratedDocument<T, TMethods, TVirtuals>;
767
771
 
768
772
  aggregate<R = any>(pipeline?: PipelineStage[], options?: mongodb.AggregateOptions, callback?: Callback<R[]>): Aggregate<Array<R>>;
769
773
  aggregate<R = any>(pipeline: PipelineStage[], cb: Function): Aggregate<Array<R>>;
@@ -1217,7 +1221,7 @@ declare module 'mongoose' {
1217
1221
  /** optional query options like sort, limit, etc */
1218
1222
  options?: any;
1219
1223
  /** deep populate */
1220
- populate?: PopulateOptions | Array<PopulateOptions>;
1224
+ populate?: string | PopulateOptions | (string | PopulateOptions)[];
1221
1225
  /**
1222
1226
  * If true Mongoose will always set `path` to an array, if false Mongoose will
1223
1227
  * always set `path` to a document. Inferred from schema by default.
@@ -1254,7 +1258,6 @@ declare module 'mongoose' {
1254
1258
  type SchemaPreOptions = { document?: boolean, query?: boolean };
1255
1259
  type SchemaPostOptions = { document?: boolean, query?: boolean };
1256
1260
 
1257
- type ExtractQueryHelpers<M> = M extends Model<any, infer TQueryHelpers, any, any> ? TQueryHelpers : {};
1258
1261
  type ExtractVirtuals<M> = M extends Model<any, any, any, infer TVirtuals> ? TVirtuals : {};
1259
1262
 
1260
1263
  type IndexDirection = 1 | -1 | '2d' | '2dsphere' | 'geoHaystack' | 'hashed' | 'text';
@@ -1265,7 +1268,7 @@ declare module 'mongoose' {
1265
1268
  type PostMiddlewareFunction<ThisType, ResType = any> = (this: ThisType, res: ResType, next: (err?: CallbackError) => void) => void | Promise<void>;
1266
1269
  type ErrorHandlingMiddlewareFunction<ThisType, ResType = any> = (this: ThisType, err: NativeError, res: ResType, next: (err?: CallbackError) => void) => void;
1267
1270
 
1268
- class Schema<DocType = any, M = Model<DocType, any, any, any>, TInstanceMethods = any> extends events.EventEmitter {
1271
+ class Schema<DocType = any, M = Model<DocType, any, any, any>, TInstanceMethods = any, TQueryHelpers = any> extends events.EventEmitter {
1269
1272
  /**
1270
1273
  * Create a new schema
1271
1274
  */
@@ -1312,11 +1315,11 @@ declare module 'mongoose' {
1312
1315
  loadClass(model: Function, onlyVirtuals?: boolean): this;
1313
1316
 
1314
1317
  /** Adds an instance method to documents constructed from Models compiled from this schema. */
1315
- method(name: string, fn: (this: HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>, ...args: any[]) => any, opts?: any): this;
1316
- method(obj: { [name: string]: (this: HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>, ...args: any[]) => any }): this;
1318
+ method<Context = any>(name: string, fn: (this: Context, ...args: any[]) => any, opts?: any): this;
1319
+ method(obj: Partial<TInstanceMethods>): this;
1317
1320
 
1318
1321
  /** Object of currently defined methods on this schema. */
1319
- methods: { [name: string]: (this: HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>, ...args: any[]) => any };
1322
+ methods: { [F in keyof TInstanceMethods]: TInstanceMethods[F] };
1320
1323
 
1321
1324
  /** The original object passed to the schema constructor */
1322
1325
  obj: SchemaDefinition<SchemaDefinitionType<DocType>>;
@@ -1328,7 +1331,7 @@ declare module 'mongoose' {
1328
1331
  /** Lists all paths and their type in the schema. */
1329
1332
  paths: {
1330
1333
  [key: string]: SchemaType;
1331
- }
1334
+ };
1332
1335
 
1333
1336
  /** Returns the pathType of `path` for this schema. */
1334
1337
  pathType(path: string): string;
@@ -1337,37 +1340,37 @@ declare module 'mongoose' {
1337
1340
  plugin(fn: (schema: Schema<DocType>, opts?: any) => void, opts?: any): this;
1338
1341
 
1339
1342
  /** Defines a post hook for the model. */
1340
- post<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PostMiddlewareFunction<T>): this;
1341
- post<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
1342
- post<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: PostMiddlewareFunction<T>): this;
1343
- post<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
1344
- post<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, fn: PostMiddlewareFunction<T, Array<any>>): this;
1345
- post<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T, Array<any>>): this;
1343
+ post<T = HydratedDocument<DocType, TInstanceMethods>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PostMiddlewareFunction<T>): this;
1344
+ post<T = HydratedDocument<DocType, TInstanceMethods>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
1345
+ post<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: PostMiddlewareFunction<T>): this;
1346
+ post<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
1347
+ post<T extends Aggregate<any>>(method: 'aggregate' | RegExp, fn: PostMiddlewareFunction<T, Array<any>>): this;
1348
+ post<T extends Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T, Array<any>>): this;
1346
1349
  post<T = M>(method: 'insertMany' | RegExp, fn: PostMiddlewareFunction<T>): this;
1347
1350
  post<T = M>(method: 'insertMany' | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
1348
1351
 
1349
- post<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
1350
- post<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
1351
- post<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
1352
- post<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
1353
- post<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, fn: ErrorHandlingMiddlewareFunction<T, Array<any>>): this;
1354
- post<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T, Array<any>>): this;
1352
+ post<T = HydratedDocument<DocType, TInstanceMethods>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
1353
+ post<T = HydratedDocument<DocType, TInstanceMethods>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
1354
+ post<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
1355
+ post<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
1356
+ post<T extends Aggregate<any>>(method: 'aggregate' | RegExp, fn: ErrorHandlingMiddlewareFunction<T, Array<any>>): this;
1357
+ post<T extends Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T, Array<any>>): this;
1355
1358
  post<T = M>(method: 'insertMany' | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
1356
1359
  post<T = M>(method: 'insertMany' | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
1357
1360
 
1358
1361
  /** Defines a pre hook for the model. */
1359
- pre<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: 'save', fn: PreSaveMiddlewareFunction<T>): this;
1360
- pre<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PreMiddlewareFunction<T>): this;
1361
- pre<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
1362
- pre<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: PreMiddlewareFunction<T>): this;
1363
- pre<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
1364
- pre<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, fn: PreMiddlewareFunction<T>): this;
1365
- pre<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
1362
+ pre<T = HydratedDocument<DocType, TInstanceMethods>>(method: 'save', fn: PreSaveMiddlewareFunction<T>): this;
1363
+ pre<T = HydratedDocument<DocType, TInstanceMethods>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PreMiddlewareFunction<T>): this;
1364
+ pre<T extends Query<any, any>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
1365
+ pre<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: PreMiddlewareFunction<T>): this;
1366
+ pre<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
1367
+ pre<T extends Aggregate<any>>(method: 'aggregate' | RegExp, fn: PreMiddlewareFunction<T>): this;
1368
+ pre<T extends Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
1366
1369
  pre<T = M>(method: 'insertMany' | RegExp, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array<any>) => void | Promise<void>): this;
1367
1370
  pre<T = M>(method: 'insertMany' | RegExp, options: SchemaPreOptions, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array<any>) => void | Promise<void>): this;
1368
1371
 
1369
1372
  /** Object of currently defined query helpers on this schema. */
1370
- query: { [name: string]: (this: QueryWithHelpers<any, DocType, ExtractQueryHelpers<M>>, ...args: any[]) => any };
1373
+ query: TQueryHelpers;
1371
1374
 
1372
1375
  /** Adds a method call to the queue. */
1373
1376
  queue(name: string, args: any[]): this;
@@ -1624,7 +1627,7 @@ declare module 'mongoose' {
1624
1627
  * The default value for this path. If a function, Mongoose executes the function
1625
1628
  * and uses the return value as the default.
1626
1629
  */
1627
- default?: T | ((this: any, doc: any) => T);
1630
+ default?: T | ((this: any, doc: any) => Partial<T>);
1628
1631
 
1629
1632
  /**
1630
1633
  * The model that `populate()` should use if populating this path.
@@ -1685,7 +1688,7 @@ declare module 'mongoose' {
1685
1688
  enum?: Array<string | number | null> | ReadonlyArray<string | number | null> | { values: Array<string | number | null> | ReadonlyArray<string | number | null>, message?: string } | { [path: string]: string | number | null };
1686
1689
 
1687
1690
  /** The default [subtype](http://bsonspec.org/spec.html) associated with this buffer when it is stored in MongoDB. Only allowed for buffer paths */
1688
- subtype?: number
1691
+ subtype?: number;
1689
1692
 
1690
1693
  /** The minimum value allowed for this path. Only allowed for numbers and dates. */
1691
1694
  min?: number | NativeDate | [number, string] | [NativeDate, string] | readonly [number, string] | readonly [NativeDate, string];
@@ -2094,7 +2097,7 @@ declare module 'mongoose' {
2094
2097
  _id: this;
2095
2098
  }
2096
2099
 
2097
- class Subdocument extends Document {
2100
+ class Subdocument<IdType = any> extends Document<IdType> {
2098
2101
  $isSingleNested: true;
2099
2102
 
2100
2103
  /** Returns the top level document of this sub-document. */
@@ -2112,6 +2115,8 @@ declare module 'mongoose' {
2112
2115
 
2113
2116
  type QueryWithHelpers<ResultType, DocType, THelpers = {}, RawDocType = DocType> = Query<ResultType, DocType, THelpers, RawDocType> & THelpers;
2114
2117
 
2118
+ type UnpackedIntersection<T, U> = T extends (infer V)[] ? (V & U)[] : T & U;
2119
+
2115
2120
  class Query<ResultType, DocType, THelpers = {}, RawDocType = DocType> {
2116
2121
  _mongooseOptions: MongooseQueryOptions;
2117
2122
 
@@ -2315,7 +2320,7 @@ declare module 'mongoose' {
2315
2320
  j(val: boolean | null): this;
2316
2321
 
2317
2322
  /** Sets the lean option. */
2318
- lean<LeanResultType = RawDocType extends Document ? LeanDocumentOrArray<ResultType> : LeanDocumentOrArrayWithRawType<ResultType, RawDocType>>(val?: boolean | any): QueryWithHelpers<LeanResultType, DocType, THelpers, RawDocType>;
2323
+ lean<LeanResultType = RawDocType extends Document ? LeanDocumentOrArray<ResultType> : LeanDocumentOrArrayWithRawType<ResultType, Require_id<RawDocType>>>(val?: boolean | any): QueryWithHelpers<LeanResultType, DocType, THelpers, RawDocType>;
2319
2324
 
2320
2325
  /** Specifies the maximum number of documents the query will return. */
2321
2326
  limit(val: number): this;
@@ -2332,7 +2337,7 @@ declare module 'mongoose' {
2332
2337
  * Runs a function `fn` and treats the return value of `fn` as the new value
2333
2338
  * for the query to resolve to.
2334
2339
  */
2335
- map<MappedType>(fn: (doc: ResultType) => MappedType): QueryWithHelpers<MappedType, DocType, THelpers, RawDocType>;
2340
+ transform<MappedType>(fn: (doc: ResultType) => MappedType): QueryWithHelpers<MappedType, DocType, THelpers, RawDocType>;
2336
2341
 
2337
2342
  /** Specifies an `$maxDistance` query condition. When called with one argument, the most recent path passed to `where()` is used. */
2338
2343
  maxDistance(val: number): this;
@@ -2394,11 +2399,11 @@ declare module 'mongoose' {
2394
2399
  polygon(path: string, ...coordinatePairs: number[][]): this;
2395
2400
 
2396
2401
  /** Specifies paths which should be populated with other documents. */
2397
- populate<Paths = {}>(path: string | any, select?: string | any, model?: string | Model<any, THelpers>, match?: any): QueryWithHelpers<ResultType & Paths, DocType, THelpers, RawDocType>;
2398
- populate<Paths = {}>(options: PopulateOptions | Array<PopulateOptions>): QueryWithHelpers<ResultType & Paths, DocType, THelpers, RawDocType>;
2402
+ populate<Paths = {}>(path: string | any, select?: string | any, model?: string | Model<any, THelpers>, match?: any): QueryWithHelpers<UnpackedIntersection<ResultType, Paths>, DocType, THelpers, RawDocType>;
2403
+ populate<Paths = {}>(options: PopulateOptions | Array<PopulateOptions>): QueryWithHelpers<UnpackedIntersection<ResultType, Paths>, DocType, THelpers, RawDocType>;
2399
2404
 
2400
2405
  /** Get/set the current projection (AKA fields). Pass `null` to remove the current projection. */
2401
- projection(fields?: any | null): any;
2406
+ projection(fields?: any | null): this;
2402
2407
 
2403
2408
  /** Determines the MongoDB nodes from which to read. */
2404
2409
  read(pref: string | mongodb.ReadPreferenceMode, tags?: any[]): this;
@@ -2674,7 +2679,9 @@ declare module 'mongoose' {
2674
2679
  };
2675
2680
 
2676
2681
  export type FlattenMaps<T> = {
2677
- [K in keyof T]: T[K] extends Map<any, any> ? AnyObject : FlattenMaps<T[K]>;
2682
+ [K in keyof T]: T[K] extends Map<any, any>
2683
+ ? AnyObject : T[K] extends TreatAsPrimitives
2684
+ ? T[K] : FlattenMaps<T[K]>;
2678
2685
  };
2679
2686
 
2680
2687
  type actualPrimitives = string | boolean | number | bigint | symbol | null | undefined;
@@ -2704,10 +2711,6 @@ declare module 'mongoose' {
2704
2711
  export type SchemaDefinitionType<T> = T extends Document ? Omit<T, Exclude<keyof Document, '_id' | 'id' | '__v'>> : T;
2705
2712
  export type LeanDocument<T> = Omit<_LeanDocument<T>, Exclude<keyof Document, '_id' | 'id' | '__v'> | '$isSingleNested'>;
2706
2713
 
2707
- type DeepPartial<T> = {
2708
- [K in keyof T]?: DeepPartial<T[K]>;
2709
- }
2710
-
2711
2714
  export type LeanDocumentOrArray<T> = 0 extends (1 & T) ? T :
2712
2715
  T extends unknown[] ? LeanDocument<T[number]>[] :
2713
2716
  T extends Document ? LeanDocument<T> :
@@ -2762,6 +2765,13 @@ declare module 'mongoose' {
2762
2765
  }
2763
2766
 
2764
2767
  class Aggregate<R> {
2768
+ /**
2769
+ * Returns an asyncIterator for use with [`for/await/of` loops](https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js
2770
+ * You do not need to call this function explicitly, the JavaScript runtime
2771
+ * will call it for you.
2772
+ */
2773
+ [Symbol.asyncIterator](): AsyncIterableIterator<Unpacked<R>>;
2774
+
2765
2775
  /**
2766
2776
  * Sets an option on this aggregation. This function will be deprecated in a
2767
2777
  * future release. */
@@ -3016,12 +3026,11 @@ declare module 'mongoose' {
3016
3026
 
3017
3027
  export interface Facet {
3018
3028
  /** [`$facet` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/facet/) */
3019
- $facet: Record<
3020
- string,
3021
- Exclude<PipelineStage, PipelineStage.CollStats | PipelineStage.Facet | PipelineStage.GeoNear | PipelineStage.IndexStats | PipelineStage.Out | PipelineStage.Merge | PipelineStage.PlanCacheStats>[]
3022
- >
3029
+ $facet: Record<string, FacetPipelineStage[]>
3023
3030
  }
3024
3031
 
3032
+ export type FacetPipelineStage = Exclude<PipelineStage, PipelineStage.CollStats | PipelineStage.Facet | PipelineStage.GeoNear | PipelineStage.IndexStats | PipelineStage.Out | PipelineStage.Merge | PipelineStage.PlanCacheStats>
3033
+
3025
3034
  export interface GeoNear {
3026
3035
  /** [`$geoNear` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/geoNear/) */
3027
3036
  $geoNear: {
@@ -3054,10 +3063,7 @@ declare module 'mongoose' {
3054
3063
 
3055
3064
  export interface Group {
3056
3065
  /** [`$group` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/group) */
3057
- $group: {
3058
- _id: any
3059
- [key: string]: { [op in AccumulatorOperator]?: any }
3060
- }
3066
+ $group: { _id: any } | { [key: string]: { [op in AccumulatorOperator]?: any } }
3061
3067
  }
3062
3068
 
3063
3069
  export interface IndexStats {
@@ -3098,7 +3104,7 @@ declare module 'mongoose' {
3098
3104
  into: string | { db: string; coll: string }
3099
3105
  on?: string | string[]
3100
3106
  let?: Record<string, any>
3101
- whenMatched?: 'replace' | 'keepExisting' | 'merge' | 'fail' | 'pipeline'
3107
+ whenMatched?: 'replace' | 'keepExisting' | 'merge' | 'fail' | Extract<PipelineStage, PipelineStage.AddFields | PipelineStage.Set | PipelineStage.Project | PipelineStage.Unset | PipelineStage.ReplaceRoot | PipelineStage.ReplaceWith>[]
3102
3108
  whenNotMatched?: 'insert' | 'discard' | 'fail'
3103
3109
  }
3104
3110
  }
@@ -3115,7 +3121,7 @@ declare module 'mongoose' {
3115
3121
 
3116
3122
  export interface Project {
3117
3123
  /** [`$project` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/project/) */
3118
- $project: { _id?: 0 | false; [field: string]: any }
3124
+ $project: { [field: string]: any }
3119
3125
  }
3120
3126
 
3121
3127
  export interface Redact {
package/lib/aggregate.js CHANGED
@@ -892,7 +892,7 @@ Aggregate.prototype.collation = function(collation) {
892
892
  * const res = await Model.aggregate().facet({
893
893
  * books: [{ groupBy: '$author' }],
894
894
  * price: [{ $bucketAuto: { groupBy: '$price', buckets: 2 } }]
895
- * });
895
+ * });
896
896
  *
897
897
  * // Output: { books: [...], price: [{...}, {...}] }
898
898
  *
package/lib/connection.js CHANGED
@@ -43,10 +43,10 @@ const noPasswordAuthMechanisms = [
43
43
  * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
44
44
  * @event `connecting`: Emitted when `connection.openUri()` is executed on this connection.
45
45
  * @event `connected`: Emitted when this connection successfully connects to the db. May be emitted _multiple_ times in `reconnected` scenarios.
46
- * @event `open`: Emitted after we `connected` and `onOpen` is executed on all of this connections models.
46
+ * @event `open`: Emitted after we `connected` and `onOpen` is executed on all of this connection's models.
47
47
  * @event `disconnecting`: Emitted when `connection.close()` was executed.
48
48
  * @event `disconnected`: Emitted after getting disconnected from the db.
49
- * @event `close`: Emitted after we `disconnected` and `onClose` executed on all of this connections models.
49
+ * @event `close`: Emitted after we `disconnected` and `onClose` executed on all of this connection's models.
50
50
  * @event `reconnected`: Emitted after we `connected` and subsequently `disconnected`, followed by successfully another successful connection.
51
51
  * @event `error`: Emitted when an error occurs on this connection.
52
52
  * @event `fullsetup`: Emitted after the driver has connected to primary and all secondaries if specified in the connection string.
@@ -1082,8 +1082,12 @@ Connection.prototype.model = function(name, schema, collection, options) {
1082
1082
  schema = false;
1083
1083
  }
1084
1084
 
1085
- if (utils.isObject(schema) && !(schema instanceof this.base.Schema)) {
1086
- schema = new Schema(schema);
1085
+ if (utils.isObject(schema)) {
1086
+ if (!schema.instanceOfSchema) {
1087
+ schema = new Schema(schema);
1088
+ } else if (!(schema instanceof this.base.Schema)) {
1089
+ schema = schema._clone(this.base.Schema);
1090
+ }
1087
1091
  }
1088
1092
  if (schema && !schema.instanceOfSchema) {
1089
1093
  throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
@@ -1359,7 +1363,7 @@ Connection.prototype.setClient = function setClient(client) {
1359
1363
  if (!(client instanceof mongodb.MongoClient)) {
1360
1364
  throw new MongooseError('Must call `setClient()` with an instance of MongoClient');
1361
1365
  }
1362
- if (this.client != null || this.readyState !== STATES.disconnected) {
1366
+ if (this.readyState !== STATES.disconnected) {
1363
1367
  throw new MongooseError('Cannot call `setClient()` on a connection that is already connected.');
1364
1368
  }
1365
1369
  if (client.topology == null) {
@@ -467,7 +467,7 @@ function _nextDoc(ctx, doc, pop, callback) {
467
467
  });
468
468
  }
469
469
 
470
- _create(ctx, doc, pop, (err, doc) => {
470
+ ctx.query._completeOne(doc, null, (err, doc) => {
471
471
  if (err != null) {
472
472
  return callback(err);
473
473
  }
@@ -496,22 +496,4 @@ function _waitForCursor(ctx, cb) {
496
496
  });
497
497
  }
498
498
 
499
- /*!
500
- * Convert a raw doc into a full mongoose doc.
501
- */
502
-
503
- function _create(ctx, doc, populatedIds, cb) {
504
- const instance = helpers.createModel(ctx.query.model, doc, ctx.query._fields);
505
- const opts = populatedIds ?
506
- { populated: populatedIds } :
507
- undefined;
508
-
509
- instance.$init(doc, opts, function(err) {
510
- if (err) {
511
- return cb(err);
512
- }
513
- cb(null, instance);
514
- });
515
- }
516
-
517
499
  module.exports = QueryCursor;
package/lib/document.js CHANGED
@@ -91,12 +91,14 @@ function Document(obj, fields, skipId, options) {
91
91
  }
92
92
 
93
93
  this.$__ = new InternalCache;
94
- this.$__.emitter = new EventEmitter();
95
94
  this.$isNew = 'isNew' in options ? options.isNew : true;
96
95
 
97
96
  if ('priorDoc' in options) {
98
97
  this.$__.priorDoc = options.priorDoc;
99
98
  }
99
+ if (skipId) {
100
+ this.$__.skipId = skipId;
101
+ }
100
102
 
101
103
  if (obj != null && typeof obj !== 'object') {
102
104
  throw new ObjectParameterError(obj, 'obj', 'Document');
@@ -125,14 +127,15 @@ function Document(obj, fields, skipId, options) {
125
127
  this.$__.activePaths.require(path);
126
128
  }
127
129
 
128
- this.$__.emitter.setMaxListeners(0);
129
-
130
130
  let exclude = null;
131
131
 
132
132
  // determine if this doc is a result of a query with
133
133
  // excluded fields
134
134
  if (utils.isPOJO(fields)) {
135
135
  exclude = isExclusive(fields);
136
+
137
+ this.$__.fields = fields;
138
+ this.$__.exclude = exclude;
136
139
  }
137
140
 
138
141
  const hasIncludedChildren = exclude === false && fields ?
@@ -145,7 +148,7 @@ function Document(obj, fields, skipId, options) {
145
148
  // By default, defaults get applied **before** setting initial values
146
149
  // Re: gh-6155
147
150
  if (defaults) {
148
- $__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, true, {
151
+ $__applyDefaults(this, fields, exclude, hasIncludedChildren, true, {
149
152
  isNew: this.$isNew
150
153
  });
151
154
  }
@@ -167,13 +170,11 @@ function Document(obj, fields, skipId, options) {
167
170
  // see the full doc rather than an empty one, unless they opt out.
168
171
  // Re: gh-3781, gh-6155
169
172
  if (options.willInit && defaults) {
170
- EventEmitter.prototype.once.call(this, 'init', () => {
171
- $__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false, options.skipDefaults, {
172
- isNew: this.$isNew
173
- });
174
- });
173
+ if (options.skipDefaults) {
174
+ this.$__.skipDefaults = options.skipDefaults;
175
+ }
175
176
  } else if (defaults) {
176
- $__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false, options.skipDefaults, {
177
+ $__applyDefaults(this, fields, exclude, hasIncludedChildren, false, options.skipDefaults, {
177
178
  isNew: this.$isNew
178
179
  });
179
180
  }
@@ -222,6 +223,15 @@ utils.each(
222
223
  'removeAllListeners', 'addListener'],
223
224
  function(emitterFn) {
224
225
  Document.prototype[emitterFn] = function() {
226
+ // Delay creating emitter until necessary because emitters take up a lot of memory,
227
+ // especially for subdocuments.
228
+ if (!this.$__.emitter) {
229
+ if (emitterFn === 'emit') {
230
+ return;
231
+ }
232
+ this.$__.emitter = new EventEmitter();
233
+ this.$__.emitter.setMaxListeners(0);
234
+ }
225
235
  return this.$__.emitter[emitterFn].apply(this.$__.emitter, arguments);
226
236
  };
227
237
  Document.prototype[`$${emitterFn}`] = Document.prototype[emitterFn];
@@ -416,12 +426,18 @@ function $__hasIncludedChildren(fields) {
416
426
  const keys = Object.keys(fields);
417
427
 
418
428
  for (const key of keys) {
429
+ if (key.indexOf('.') === -1) {
430
+ hasIncludedChildren[key] = 1;
431
+ continue;
432
+ }
419
433
  const parts = key.split('.');
420
- const c = [];
434
+ let c = parts[0];
421
435
 
422
- for (const part of parts) {
423
- c.push(part);
424
- hasIncludedChildren[c.join('.')] = 1;
436
+ for (let i = 0; i < parts.length; ++i) {
437
+ hasIncludedChildren[c] = 1;
438
+ if (i + 1 < parts.length) {
439
+ c = c + '.' + parts[i + 1];
440
+ }
425
441
  }
426
442
  }
427
443
 
@@ -432,7 +448,7 @@ function $__hasIncludedChildren(fields) {
432
448
  * ignore
433
449
  */
434
450
 
435
- function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
451
+ function $__applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
436
452
  const paths = Object.keys(doc.$__schema.paths);
437
453
  const plen = paths.length;
438
454
 
@@ -441,7 +457,7 @@ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isB
441
457
  let curPath = '';
442
458
  const p = paths[i];
443
459
 
444
- if (p === '_id' && skipId) {
460
+ if (p === '_id' && doc.$__.skipId) {
445
461
  continue;
446
462
  }
447
463
 
@@ -720,13 +736,8 @@ Document.prototype.$init = function() {
720
736
  return this.constructor.prototype.init.apply(this, arguments);
721
737
  };
722
738
 
723
- /*!
724
- * ignore
725
- */
726
-
727
739
  Document.prototype.$__init = function(doc, opts) {
728
740
  this.$isNew = false;
729
- this.$init = true;
730
741
  opts = opts || {};
731
742
 
732
743
  // handle docs with populated paths
@@ -761,6 +772,12 @@ Document.prototype.$__init = function(doc, opts) {
761
772
  this.constructor.emit('init', this);
762
773
 
763
774
  this.$__._id = this._id;
775
+
776
+ const hasIncludedChildren = this.$__.exclude === false && this.$__.fields ?
777
+ $__hasIncludedChildren(this.$__.fields) :
778
+ {};
779
+ $__applyDefaults(this, this.$__.fields, this.$__.exclude, hasIncludedChildren, false, this.$__.skipDefaults);
780
+
764
781
  return this;
765
782
  };
766
783
 
@@ -820,8 +837,7 @@ function init(self, obj, doc, opts, prefix) {
820
837
  if (obj[i] === null) {
821
838
  doc[i] = schema._castNullish(null);
822
839
  } else if (obj[i] !== undefined) {
823
- const intCache = obj[i].$__ || {};
824
- const wasPopulated = intCache.wasPopulated || null;
840
+ const wasPopulated = obj[i].$__ == null ? null : obj[i].$__.wasPopulated;
825
841
 
826
842
  if (schema && !wasPopulated) {
827
843
  try {
@@ -988,10 +1004,13 @@ Document.prototype.$session = function $session(session) {
988
1004
  'called `endSession()` on the session you are passing to `$session()`.');
989
1005
  }
990
1006
 
991
- this.$__.session = session;
1007
+ if (session == null && this.$__.session == null) {
1008
+ return;
1009
+ }
992
1010
 
1011
+ this.$__.session = session;
993
1012
 
994
- if (!this.$__.isSubDocument) {
1013
+ if (!this.$isSubdocument) {
995
1014
  const subdocs = this.$getAllSubdocs();
996
1015
  for (const child of subdocs) {
997
1016
  child.$session(session);
@@ -1143,13 +1162,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1143
1162
  }
1144
1163
 
1145
1164
  if (pathtype === 'real' || pathtype === 'virtual') {
1146
- // Check for setting single embedded schema to document (gh-3535)
1147
- let p = path[key];
1148
- if (this.$__schema.paths[pathName] &&
1149
- this.$__schema.paths[pathName].$isSingleNested &&
1150
- path[key] instanceof Document) {
1151
- p = p.toObject({ virtuals: false, transform: false });
1152
- }
1165
+ const p = path[key];
1153
1166
  this.$set(prefix + key, p, constructing, options);
1154
1167
  } else if (pathtype === 'nested' && path[key] instanceof Document) {
1155
1168
  this.$set(prefix + key,
@@ -1410,7 +1423,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1410
1423
  didPopulate = true;
1411
1424
  }
1412
1425
 
1413
- if (this.$__schema.singleNestedPaths[path] == null) {
1426
+ if (this.$__schema.singleNestedPaths[path] == null && (!refMatches || !schema.$isSingleNested || !val.$__)) {
1414
1427
  // If this path is underneath a single nested schema, we'll call the setter
1415
1428
  // later in `$__set()` because we don't take `_doc` when we iterate through
1416
1429
  // a single nested doc. That's to make sure we get the correct context.
@@ -1468,9 +1481,9 @@ Document.prototype.$set = function $set(path, val, type, options) {
1468
1481
  }
1469
1482
 
1470
1483
  if (shouldSet) {
1471
- const doc = this.$__.isSubDocument ? this.ownerDocument() : this;
1484
+ const doc = this.$isSubdocument ? this.ownerDocument() : this;
1472
1485
  const savedState = doc.$__.savedState;
1473
- const savedStatePath = this.$__.isSubDocument ? this.$__.fullPath + '.' + path : path;
1486
+ const savedStatePath = this.$isSubdocument ? this.$__.fullPath + '.' + path : path;
1474
1487
  if (savedState != null) {
1475
1488
  const firstDot = savedStatePath.indexOf('.');
1476
1489
  const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
@@ -1844,7 +1857,7 @@ Document.prototype.$__path = function(path) {
1844
1857
 
1845
1858
  Document.prototype.markModified = function(path, scope) {
1846
1859
  this.$__.activePaths.modify(path);
1847
- if (scope != null && !this.$__.isSubDocument) {
1860
+ if (scope != null && !this.$isSubdocument) {
1848
1861
  this.$__.pathsToScopes = this.$__pathsToScopes || {};
1849
1862
  this.$__.pathsToScopes[path] = scope;
1850
1863
  }
@@ -2061,11 +2074,15 @@ Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
2061
2074
 
2062
2075
  Document.prototype.isModified = function(paths, modifiedPaths) {
2063
2076
  if (paths) {
2077
+ const directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
2078
+ if (directModifiedPaths.length === 0) {
2079
+ return false;
2080
+ }
2081
+
2064
2082
  if (!Array.isArray(paths)) {
2065
- paths = paths.split(' ');
2083
+ paths = paths.indexOf(' ') === -1 ? [paths] : paths.split(' ');
2066
2084
  }
2067
2085
  const modified = modifiedPaths || this[documentModifiedPaths]();
2068
- const directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
2069
2086
  const isModifiedChild = paths.some(function(path) {
2070
2087
  return !!~modified.indexOf(path);
2071
2088
  });
@@ -2222,7 +2239,9 @@ Document.prototype.isSelected = function isSelected(path) {
2222
2239
  if (this.$__.selected == null) {
2223
2240
  return true;
2224
2241
  }
2225
-
2242
+ if (!path) {
2243
+ return false;
2244
+ }
2226
2245
  if (path === '_id') {
2227
2246
  return this.$__.selected._id !== 0;
2228
2247
  }
@@ -2372,7 +2391,7 @@ Document.prototype.validate = function(pathsToValidate, options, callback) {
2372
2391
  let parallelValidate;
2373
2392
  this.$op = 'validate';
2374
2393
 
2375
- if (this.$__.isSubDocument != null) {
2394
+ if (this.$isSubdocument != null) {
2376
2395
  // Skip parallel validate check for subdocuments
2377
2396
  } else if (this.$__.validating) {
2378
2397
  parallelValidate = new ParallelValidateError(this, {
@@ -3119,7 +3138,7 @@ Document.prototype.$__reset = function reset() {
3119
3138
  doc.$__reset();
3120
3139
  if (doc.$parent() === _this) {
3121
3140
  _this.$__.activePaths.init(doc.$basePath);
3122
- } else if (doc.$parent() != null && doc.$parent().$__.isSubDocument) {
3141
+ } else if (doc.$parent() != null && doc.$parent().$isSubdocument) {
3123
3142
  // If map path underneath subdocument, may end up with a case where
3124
3143
  // map path is modified but parent still needs to be reset. See gh-10295
3125
3144
  doc.$parent().$__reset();
@@ -3971,7 +3990,7 @@ Document.prototype.ownerDocument = function() {
3971
3990
  */
3972
3991
 
3973
3992
  Document.prototype.parent = function() {
3974
- if (this.$__.isSubDocument || this.$__.wasPopulated) {
3993
+ if (this.$isSubdocument || this.$__.wasPopulated) {
3975
3994
  return this.$__.parent;
3976
3995
  }
3977
3996
  return this;
@@ -19,7 +19,7 @@ exports.modifiedPaths = modifiedPaths;
19
19
  function flatten(update, path, options, schema) {
20
20
  let keys;
21
21
  if (update && isMongooseObject(update) && !Buffer.isBuffer(update)) {
22
- keys = Object.keys(update.toObject({ transform: false, virtuals: false }));
22
+ keys = Object.keys(update.toObject({ transform: false, virtuals: false }) || {});
23
23
  } else {
24
24
  keys = Object.keys(update || {});
25
25
  }
@@ -22,6 +22,12 @@ module.exports = function cleanModifiedSubpaths(doc, path, options) {
22
22
  if (modifiedPath.startsWith(path + '.')) {
23
23
  delete doc.$__.activePaths.states.modify[modifiedPath];
24
24
  ++deleted;
25
+
26
+ if (doc.$isSubdocument) {
27
+ const owner = doc.ownerDocument();
28
+ const fullPath = doc.$__fullPath(modifiedPath);
29
+ delete owner.$__.activePaths.states.modify[fullPath];
30
+ }
25
31
  }
26
32
  }
27
33
  return deleted;