mongoose 8.9.6 → 8.10.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.
@@ -21,6 +21,7 @@ const isOperator = require('../helpers/query/isOperator');
21
21
  const util = require('util');
22
22
  const utils = require('../utils');
23
23
  const castToNumber = require('./operators/helpers').castToNumber;
24
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
24
25
  const geospatial = require('./operators/geospatial');
25
26
  const getDiscriminatorByValue = require('../helpers/discriminator/getDiscriminatorByValue');
26
27
 
@@ -403,6 +404,9 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
403
404
  opts.arrayPathIndex = i;
404
405
  }
405
406
  }
407
+ if (options.hydratedPopulatedDocs) {
408
+ opts.hydratedPopulatedDocs = options.hydratedPopulatedDocs;
409
+ }
406
410
  rawValue[i] = caster.applySetters(rawValue[i], doc, init, void 0, opts);
407
411
  }
408
412
  } catch (e) {
@@ -697,6 +701,23 @@ handle.$ne = SchemaArray.prototype._castForQuery;
697
701
  handle.$nin = SchemaType.prototype.$conditionalHandlers.$nin;
698
702
  handle.$in = SchemaType.prototype.$conditionalHandlers.$in;
699
703
 
704
+ /**
705
+ * Returns this schema type's representation in a JSON schema.
706
+ *
707
+ * @param [options]
708
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
709
+ * @returns {Object} JSON schema properties
710
+ */
711
+
712
+ SchemaArray.prototype.toJSONSchema = function toJSONSchema(options) {
713
+ const embeddedSchemaType = this.getEmbeddedSchemaType();
714
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
715
+ return {
716
+ ...createJSONSchemaTypeDefinition('array', 'array', options?.useBsonType, isRequired),
717
+ items: embeddedSchemaType.toJSONSchema(options)
718
+ };
719
+ };
720
+
700
721
  /*!
701
722
  * Module exports.
702
723
  */
@@ -7,6 +7,7 @@
7
7
  const CastError = require('../error/cast');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castBigInt = require('../cast/bigint');
10
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
10
11
 
11
12
  /**
12
13
  * BigInt SchemaType constructor.
@@ -240,6 +241,19 @@ SchemaBigInt.prototype._castNullish = function _castNullish(v) {
240
241
  return v;
241
242
  };
242
243
 
244
+ /**
245
+ * Returns this schema type's representation in a JSON schema.
246
+ *
247
+ * @param [options]
248
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
249
+ * @returns {Object} JSON schema properties
250
+ */
251
+
252
+ SchemaBigInt.prototype.toJSONSchema = function toJSONSchema(options) {
253
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
254
+ return createJSONSchemaTypeDefinition('string', 'long', options?.useBsonType, isRequired);
255
+ };
256
+
243
257
  /*!
244
258
  * Module exports.
245
259
  */
@@ -7,6 +7,7 @@
7
7
  const CastError = require('../error/cast');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castBoolean = require('../cast/boolean');
10
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
10
11
 
11
12
  /**
12
13
  * Boolean SchemaType constructor.
@@ -290,6 +291,19 @@ SchemaBoolean.prototype._castNullish = function _castNullish(v) {
290
291
  return v;
291
292
  };
292
293
 
294
+ /**
295
+ * Returns this schema type's representation in a JSON schema.
296
+ *
297
+ * @param [options]
298
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
299
+ * @returns {Object} JSON schema properties
300
+ */
301
+
302
+ SchemaBoolean.prototype.toJSONSchema = function toJSONSchema(options) {
303
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
304
+ return createJSONSchemaTypeDefinition('boolean', 'bool', options?.useBsonType, isRequired);
305
+ };
306
+
293
307
  /*!
294
308
  * Module exports.
295
309
  */
@@ -7,6 +7,7 @@
7
7
  const MongooseBuffer = require('../types/buffer');
8
8
  const SchemaBufferOptions = require('../options/schemaBufferOptions');
9
9
  const SchemaType = require('../schemaType');
10
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
10
11
  const handleBitwiseOperator = require('./operators/bitwise');
11
12
  const utils = require('../utils');
12
13
 
@@ -140,7 +141,7 @@ SchemaBuffer.prototype.checkRequired = function(value, doc) {
140
141
  * @api private
141
142
  */
142
143
 
143
- SchemaBuffer.prototype.cast = function(value, doc, init) {
144
+ SchemaBuffer.prototype.cast = function(value, doc, init, prev, options) {
144
145
  let ret;
145
146
  if (SchemaType._isRef(this, value, doc, init)) {
146
147
  if (value && value.isMongooseBuffer) {
@@ -167,7 +168,7 @@ SchemaBuffer.prototype.cast = function(value, doc, init) {
167
168
  }
168
169
 
169
170
  if (value == null || utils.isNonBuiltinObject(value)) {
170
- return this._castRef(value, doc, init);
171
+ return this._castRef(value, doc, init, options);
171
172
  }
172
173
  }
173
174
 
@@ -300,6 +301,19 @@ SchemaBuffer.prototype.castForQuery = function($conditional, val, context) {
300
301
  return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
301
302
  };
302
303
 
304
+ /**
305
+ * Returns this schema type's representation in a JSON schema.
306
+ *
307
+ * @param [options]
308
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
309
+ * @returns {Object} JSON schema properties
310
+ */
311
+
312
+ SchemaBuffer.prototype.toJSONSchema = function toJSONSchema(options) {
313
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
314
+ return createJSONSchemaTypeDefinition('string', 'binData', options?.useBsonType, isRequired);
315
+ };
316
+
303
317
  /*!
304
318
  * Module exports.
305
319
  */
@@ -8,6 +8,7 @@ const MongooseError = require('../error/index');
8
8
  const SchemaDateOptions = require('../options/schemaDateOptions');
9
9
  const SchemaType = require('../schemaType');
10
10
  const castDate = require('../cast/date');
11
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
12
  const getConstructorName = require('../helpers/getConstructorName');
12
13
  const utils = require('../utils');
13
14
 
@@ -426,6 +427,19 @@ SchemaDate.prototype.castForQuery = function($conditional, val, context) {
426
427
  return handler.call(this, val);
427
428
  };
428
429
 
430
+ /**
431
+ * Returns this schema type's representation in a JSON schema.
432
+ *
433
+ * @param [options]
434
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
435
+ * @returns {Object} JSON schema properties
436
+ */
437
+
438
+ SchemaDate.prototype.toJSONSchema = function toJSONSchema(options) {
439
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
440
+ return createJSONSchemaTypeDefinition('string', 'date', options?.useBsonType, isRequired);
441
+ };
442
+
429
443
  /*!
430
444
  * Module exports.
431
445
  */
@@ -7,6 +7,7 @@
7
7
  const SchemaType = require('../schemaType');
8
8
  const CastError = SchemaType.CastError;
9
9
  const castDecimal128 = require('../cast/decimal128');
10
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
10
11
  const isBsonType = require('../helpers/isBsonType');
11
12
 
12
13
  /**
@@ -180,13 +181,13 @@ SchemaDecimal128.prototype.checkRequired = function checkRequired(value, doc) {
180
181
  * @api private
181
182
  */
182
183
 
183
- SchemaDecimal128.prototype.cast = function(value, doc, init) {
184
+ SchemaDecimal128.prototype.cast = function(value, doc, init, prev, options) {
184
185
  if (SchemaType._isRef(this, value, doc, init)) {
185
186
  if (isBsonType(value, 'Decimal128')) {
186
187
  return value;
187
188
  }
188
189
 
189
- return this._castRef(value, doc, init);
190
+ return this._castRef(value, doc, init, options);
190
191
  }
191
192
 
192
193
  let castDecimal128;
@@ -221,6 +222,19 @@ SchemaDecimal128.prototype.$conditionalHandlers = {
221
222
  $lte: handleSingle
222
223
  };
223
224
 
225
+ /**
226
+ * Returns this schema type's representation in a JSON schema.
227
+ *
228
+ * @param [options]
229
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
230
+ * @returns {Object} JSON schema properties
231
+ */
232
+
233
+ SchemaDecimal128.prototype.toJSONSchema = function toJSONSchema(options) {
234
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
235
+ return createJSONSchemaTypeDefinition('string', 'decimal', options?.useBsonType, isRequired);
236
+ };
237
+
224
238
  /*!
225
239
  * Module exports.
226
240
  */
@@ -12,6 +12,7 @@ const SchemaDocumentArrayOptions =
12
12
  require('../options/schemaDocumentArrayOptions');
13
13
  const SchemaType = require('../schemaType');
14
14
  const cast = require('../cast');
15
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
15
16
  const discriminator = require('../helpers/model/discriminator');
16
17
  const handleIdOption = require('../helpers/schema/handleIdOption');
17
18
  const handleSpreadDoc = require('../helpers/document/handleSpreadDoc');
@@ -651,6 +652,23 @@ function cast$elemMatch(val, context) {
651
652
  return cast(schema, val, null, this && this.$$context);
652
653
  }
653
654
 
655
+ /**
656
+ * Returns this schema type's representation in a JSON schema.
657
+ *
658
+ * @param [options]
659
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
660
+ * @returns {Object} JSON schema properties
661
+ */
662
+
663
+ SchemaDocumentArray.prototype.toJSONSchema = function toJSONSchema(options) {
664
+ const itemsTypeDefinition = createJSONSchemaTypeDefinition('object', 'object', options?.useBsonType, false);
665
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
666
+ return {
667
+ ...createJSONSchemaTypeDefinition('array', 'array', options?.useBsonType, isRequired),
668
+ items: { ...itemsTypeDefinition, ...this.schema.toJSONSchema(options) }
669
+ };
670
+ };
671
+
654
672
  /*!
655
673
  * Module exports.
656
674
  */
@@ -7,6 +7,7 @@
7
7
  const CastError = require('../error/cast');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castDouble = require('../cast/double');
10
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
10
11
 
11
12
  /**
12
13
  * Double SchemaType constructor.
@@ -204,6 +205,18 @@ SchemaDouble.prototype.$conditionalHandlers = {
204
205
  $lte: handleSingle
205
206
  };
206
207
 
208
+ /**
209
+ * Returns this schema type's representation in a JSON schema.
210
+ *
211
+ * @param [options]
212
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
213
+ * @returns {Object} JSON schema properties
214
+ */
215
+
216
+ SchemaDouble.prototype.toJSONSchema = function toJSONSchema(options) {
217
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
218
+ return createJSONSchemaTypeDefinition('number', 'double', options?.useBsonType, isRequired);
219
+ };
207
220
 
208
221
  /*!
209
222
  * Module exports.
@@ -7,6 +7,7 @@
7
7
  const CastError = require('../error/cast');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castInt32 = require('../cast/int32');
10
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
10
11
  const handleBitwiseOperator = require('./operators/bitwise');
11
12
 
12
13
  /**
@@ -246,6 +247,19 @@ SchemaInt32.prototype.castForQuery = function($conditional, val, context) {
246
247
  }
247
248
  };
248
249
 
250
+ /**
251
+ * Returns this schema type's representation in a JSON schema.
252
+ *
253
+ * @param [options]
254
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
255
+ * @returns {Object} JSON schema properties
256
+ */
257
+
258
+ SchemaInt32.prototype.toJSONSchema = function toJSONSchema(options) {
259
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
260
+ return createJSONSchemaTypeDefinition('number', 'int', options?.useBsonType, isRequired);
261
+ };
262
+
249
263
 
250
264
  /*!
251
265
  * Module exports.
package/lib/schema/map.js CHANGED
@@ -7,6 +7,8 @@
7
7
  const MongooseMap = require('../types/map');
8
8
  const SchemaMapOptions = require('../options/schemaMapOptions');
9
9
  const SchemaType = require('../schemaType');
10
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
+
10
12
  /*!
11
13
  * ignore
12
14
  */
@@ -67,6 +69,39 @@ class SchemaMap extends SchemaType {
67
69
  }
68
70
  return schematype;
69
71
  }
72
+
73
+ /**
74
+ * Returns the embedded schema type (i.e. the `.$*` path)
75
+ */
76
+ getEmbeddedSchemaType() {
77
+ return this.$__schemaType;
78
+ }
79
+
80
+ /**
81
+ * Returns this schema type's representation in a JSON schema.
82
+ *
83
+ * @param [options]
84
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
85
+ * @returns {Object} JSON schema properties
86
+ */
87
+
88
+ toJSONSchema(options) {
89
+ const useBsonType = options?.useBsonType;
90
+ const embeddedSchemaType = this.getEmbeddedSchemaType();
91
+
92
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
93
+ const result = createJSONSchemaTypeDefinition('object', 'object', useBsonType, isRequired);
94
+
95
+ if (embeddedSchemaType.schema) {
96
+ result.additionalProperties = useBsonType
97
+ ? { ...embeddedSchemaType.toJSONSchema(options) }
98
+ : { ...embeddedSchemaType.toJSONSchema(options) };
99
+ } else {
100
+ result.additionalProperties = embeddedSchemaType.toJSONSchema(options);
101
+ }
102
+
103
+ return result;
104
+ }
70
105
  }
71
106
 
72
107
  /**
@@ -8,6 +8,7 @@ const MongooseError = require('../error/index');
8
8
  const SchemaNumberOptions = require('../options/schemaNumberOptions');
9
9
  const SchemaType = require('../schemaType');
10
10
  const castNumber = require('../cast/number');
11
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
12
  const handleBitwiseOperator = require('./operators/bitwise');
12
13
  const utils = require('../utils');
13
14
 
@@ -354,10 +355,10 @@ SchemaNumber.prototype.enum = function(values, message) {
354
355
  * @api private
355
356
  */
356
357
 
357
- SchemaNumber.prototype.cast = function(value, doc, init) {
358
+ SchemaNumber.prototype.cast = function(value, doc, init, prev, options) {
358
359
  if (typeof value !== 'number' && SchemaType._isRef(this, value, doc, init)) {
359
360
  if (value == null || utils.isNonBuiltinObject(value)) {
360
- return this._castRef(value, doc, init);
361
+ return this._castRef(value, doc, init, options);
361
362
  }
362
363
  }
363
364
 
@@ -442,6 +443,19 @@ SchemaNumber.prototype.castForQuery = function($conditional, val, context) {
442
443
  return val;
443
444
  };
444
445
 
446
+ /**
447
+ * Returns this schema type's representation in a JSON schema.
448
+ *
449
+ * @param [options]
450
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
451
+ * @returns {Object} JSON schema properties
452
+ */
453
+
454
+ SchemaNumber.prototype.toJSONSchema = function toJSONSchema(options) {
455
+ const isRequired = (this.options.required && typeof this.options.required !== 'function') || this.path === '_id';
456
+ return createJSONSchemaTypeDefinition('number', 'number', options?.useBsonType, isRequired);
457
+ };
458
+
445
459
  /*!
446
460
  * Module exports.
447
461
  */
@@ -7,6 +7,7 @@
7
7
  const SchemaObjectIdOptions = require('../options/schemaObjectIdOptions');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castObjectId = require('../cast/objectid');
10
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
10
11
  const getConstructorName = require('../helpers/getConstructorName');
11
12
  const oid = require('../types/objectid');
12
13
  const isBsonType = require('../helpers/isBsonType');
@@ -223,7 +224,7 @@ SchemaObjectId.prototype.checkRequired = function checkRequired(value, doc) {
223
224
  * @api private
224
225
  */
225
226
 
226
- SchemaObjectId.prototype.cast = function(value, doc, init) {
227
+ SchemaObjectId.prototype.cast = function(value, doc, init, prev, options) {
227
228
  if (!(isBsonType(value, 'ObjectId')) && SchemaType._isRef(this, value, doc, init)) {
228
229
  // wait! we may need to cast this to a document
229
230
  if ((getConstructorName(value) || '').toLowerCase() === 'objectid') {
@@ -231,7 +232,7 @@ SchemaObjectId.prototype.cast = function(value, doc, init) {
231
232
  }
232
233
 
233
234
  if (value == null || utils.isNonBuiltinObject(value)) {
234
- return this._castRef(value, doc, init);
235
+ return this._castRef(value, doc, init, options);
235
236
  }
236
237
  }
237
238
 
@@ -290,6 +291,19 @@ function resetId(v) {
290
291
  return v;
291
292
  }
292
293
 
294
+ /**
295
+ * Returns this schema type's representation in a JSON schema.
296
+ *
297
+ * @param [options]
298
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
299
+ * @returns {Object} JSON schema properties
300
+ */
301
+
302
+ SchemaObjectId.prototype.toJSONSchema = function toJSONSchema(options) {
303
+ const isRequired = (this.options.required && typeof this.options.required !== 'function') || this.path === '_id';
304
+ return createJSONSchemaTypeDefinition('string', 'objectId', options?.useBsonType, isRequired);
305
+ };
306
+
293
307
  /*!
294
308
  * Module exports.
295
309
  */
@@ -8,6 +8,7 @@ const SchemaType = require('../schemaType');
8
8
  const MongooseError = require('../error/index');
9
9
  const SchemaStringOptions = require('../options/schemaStringOptions');
10
10
  const castString = require('../cast/string');
11
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
12
  const utils = require('../utils');
12
13
  const isBsonType = require('../helpers/isBsonType');
13
14
 
@@ -586,9 +587,9 @@ SchemaString.prototype.checkRequired = function checkRequired(value, doc) {
586
587
  * @api private
587
588
  */
588
589
 
589
- SchemaString.prototype.cast = function(value, doc, init) {
590
+ SchemaString.prototype.cast = function(value, doc, init, prev, options) {
590
591
  if (typeof value !== 'string' && SchemaType._isRef(this, value, doc, init)) {
591
- return this._castRef(value, doc, init);
592
+ return this._castRef(value, doc, init, options);
592
593
  }
593
594
 
594
595
  let castString;
@@ -698,6 +699,19 @@ SchemaString.prototype.castForQuery = function($conditional, val, context) {
698
699
  }
699
700
  };
700
701
 
702
+ /**
703
+ * Returns this schema type's representation in a JSON schema.
704
+ *
705
+ * @param [options]
706
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
707
+ * @returns {Object} JSON schema properties
708
+ */
709
+
710
+ SchemaString.prototype.toJSONSchema = function toJSONSchema(options) {
711
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
712
+ return createJSONSchemaTypeDefinition('string', 'string', options?.useBsonType, isRequired);
713
+ };
714
+
701
715
  /*!
702
716
  * Module exports.
703
717
  */
@@ -12,6 +12,7 @@ const SchemaType = require('../schemaType');
12
12
  const applyDefaults = require('../helpers/document/applyDefaults');
13
13
  const $exists = require('./operators/exists');
14
14
  const castToNumber = require('./operators/helpers').castToNumber;
15
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
15
16
  const discriminator = require('../helpers/model/discriminator');
16
17
  const geospatial = require('./operators/geospatial');
17
18
  const getConstructor = require('../helpers/discriminator/getConstructor');
@@ -396,3 +397,19 @@ SchemaSubdocument.prototype.clone = function() {
396
397
  schematype._appliedDiscriminators = this._appliedDiscriminators;
397
398
  return schematype;
398
399
  };
400
+
401
+ /**
402
+ * Returns this schema type's representation in a JSON schema.
403
+ *
404
+ * @param [options]
405
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
406
+ * @returns {Object} JSON schema properties
407
+ */
408
+
409
+ SchemaSubdocument.prototype.toJSONSchema = function toJSONSchema(options) {
410
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
411
+ return {
412
+ ...this.schema.toJSONSchema(options),
413
+ ...createJSONSchemaTypeDefinition('object', 'object', options?.useBsonType, isRequired)
414
+ };
415
+ };
@@ -8,6 +8,7 @@ const MongooseBuffer = require('../types/buffer');
8
8
  const SchemaType = require('../schemaType');
9
9
  const CastError = SchemaType.CastError;
10
10
  const castUUID = require('../cast/uuid');
11
+ const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
12
  const utils = require('../utils');
12
13
  const handleBitwiseOperator = require('./operators/bitwise');
13
14
 
@@ -201,10 +202,10 @@ SchemaUUID.prototype.checkRequired = function checkRequired(value) {
201
202
  * @api private
202
203
  */
203
204
 
204
- SchemaUUID.prototype.cast = function(value, doc, init) {
205
+ SchemaUUID.prototype.cast = function(value, doc, init, prev, options) {
205
206
  if (utils.isNonBuiltinObject(value) &&
206
207
  SchemaType._isRef(this, value, doc, init)) {
207
- return this._castRef(value, doc, init);
208
+ return this._castRef(value, doc, init, options);
208
209
  }
209
210
 
210
211
  let castFn;
@@ -284,6 +285,19 @@ SchemaUUID.prototype.castForQuery = function($conditional, val, context) {
284
285
  }
285
286
  };
286
287
 
288
+ /**
289
+ * Returns this schema type's representation in a JSON schema.
290
+ *
291
+ * @param [options]
292
+ * @param [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
293
+ * @returns {Object} JSON schema properties
294
+ */
295
+
296
+ SchemaUUID.prototype.toJSONSchema = function toJSONSchema(options) {
297
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
298
+ return createJSONSchemaTypeDefinition('string', 'binData', options?.useBsonType, isRequired);
299
+ };
300
+
287
301
  /*!
288
302
  * Module exports.
289
303
  */
package/lib/schema.js CHANGED
@@ -1939,13 +1939,11 @@ Schema.prototype.pre = function(name) {
1939
1939
  * const Model = mongoose.model('Model', schema);
1940
1940
  *
1941
1941
  * const m = new Model(..);
1942
- * m.save(function(err) {
1943
- * console.log('this fires after the `post` hook');
1944
- * });
1942
+ * await m.save();
1943
+ * console.log('this fires after the `post` hook');
1945
1944
  *
1946
- * m.find(function(err, docs) {
1947
- * console.log('this fires after the post find hook');
1948
- * });
1945
+ * await m.find();
1946
+ * console.log('this fires after the post find hook');
1949
1947
  *
1950
1948
  * @param {String|RegExp|String[]} methodName The method name or regular expression to match method name
1951
1949
  * @param {Object} [options]
@@ -2382,9 +2380,15 @@ Schema.prototype.virtual = function(name, options) {
2382
2380
  const PopulateModel = this.db.model(modelNames[0]);
2383
2381
  for (let i = 0; i < populatedVal.length; ++i) {
2384
2382
  if (!populatedVal[i].$__) {
2385
- populatedVal[i] = PopulateModel.hydrate(populatedVal[i]);
2383
+ populatedVal[i] = PopulateModel.hydrate(populatedVal[i], null, { hydratedPopulatedDocs: true });
2386
2384
  }
2387
2385
  }
2386
+ const foreignField = options.foreignField;
2387
+ this.$populated(
2388
+ name,
2389
+ populatedVal.map(doc => doc == null ? doc : doc.get(typeof foreignField === 'function' ? foreignField.call(doc, doc) : foreignField)),
2390
+ { populateModelSymbol: PopulateModel }
2391
+ );
2388
2392
  }
2389
2393
  }
2390
2394
 
@@ -2882,6 +2886,92 @@ Schema.prototype._preCompile = function _preCompile() {
2882
2886
  this.plugin(idGetter, { deduplicate: true });
2883
2887
  };
2884
2888
 
2889
+ /**
2890
+ * Returns a JSON schema representation of this Schema.
2891
+ *
2892
+ * By default, returns normal [JSON schema representation](https://json-schema.org/learn/getting-started-step-by-step), which is not typically what you want to use with
2893
+ * [MongoDB's `$jsonSchema` collection option](https://www.mongodb.com/docs/manual/core/schema-validation/specify-json-schema/).
2894
+ * Use the `useBsonType: true` option to return MongoDB `$jsonSchema` syntax instead.
2895
+ *
2896
+ * In addition to types, `jsonSchema()` supports the following Mongoose validators:
2897
+ * - `enum` for strings and numbers
2898
+ *
2899
+ * #### Example:
2900
+ * const schema = new Schema({ name: String });
2901
+ * // { required: ['_id'], properties: { name: { type: ['string', 'null'] }, _id: { type: 'string' } } }
2902
+ * schema.toJSONSchema();
2903
+ *
2904
+ * // { required: ['_id'], properties: { name: { bsonType: ['string', 'null'] }, _id: { bsonType: 'objectId' } } }
2905
+ * schema.toJSONSchema({ useBsonType: true });
2906
+ *
2907
+ * @param {Object} [options]
2908
+ * @param [Boolean] [options.useBsonType=false] if true, specify each path's type using `bsonType` rather than `type` for MongoDB $jsonSchema support
2909
+ */
2910
+
2911
+ Schema.prototype.toJSONSchema = function toJSONSchema(options) {
2912
+ const useBsonType = options?.useBsonType ?? false;
2913
+ const result = useBsonType ? { required: [], properties: {} } : { type: 'object', required: [], properties: {} };
2914
+ for (const path of Object.keys(this.paths)) {
2915
+ const schemaType = this.paths[path];
2916
+
2917
+ // Skip Map embedded paths, maps will be handled seperately.
2918
+ if (schemaType._presplitPath.indexOf('$*') !== -1) {
2919
+ continue;
2920
+ }
2921
+
2922
+ // Nested paths are stored as `nested.path` in the schema type, so create nested paths in the json schema
2923
+ // when necessary.
2924
+ const isNested = schemaType._presplitPath.length > 1;
2925
+ let jsonSchemaForPath = result;
2926
+ if (isNested) {
2927
+ for (let i = 0; i < schemaType._presplitPath.length - 1; ++i) {
2928
+ const subpath = schemaType._presplitPath[i];
2929
+ if (jsonSchemaForPath.properties[subpath] == null) {
2930
+ jsonSchemaForPath.properties[subpath] = useBsonType
2931
+ ? {
2932
+ bsonType: ['object', 'null'],
2933
+ properties: {}
2934
+ }
2935
+ : {
2936
+ type: ['object', 'null'],
2937
+ properties: {}
2938
+ };
2939
+ }
2940
+ jsonSchemaForPath = jsonSchemaForPath.properties[subpath];
2941
+ }
2942
+ }
2943
+
2944
+ const lastSubpath = schemaType._presplitPath[schemaType._presplitPath.length - 1];
2945
+ let isRequired = false;
2946
+ if (path === '_id') {
2947
+ if (!jsonSchemaForPath.required) {
2948
+ jsonSchemaForPath.required = [];
2949
+ }
2950
+ jsonSchemaForPath.required.push('_id');
2951
+ isRequired = true;
2952
+ } else if (schemaType.options.required && typeof schemaType.options.required !== 'function') {
2953
+ if (!jsonSchemaForPath.required) {
2954
+ jsonSchemaForPath.required = [];
2955
+ }
2956
+ // Only `required: true` paths are required, conditional required is not required
2957
+ jsonSchemaForPath.required.push(lastSubpath);
2958
+ isRequired = true;
2959
+ }
2960
+ jsonSchemaForPath.properties[lastSubpath] = schemaType.toJSONSchema(options);
2961
+ if (schemaType.options.enum) {
2962
+ jsonSchemaForPath.properties[lastSubpath].enum = isRequired
2963
+ ? schemaType.options.enum
2964
+ : [...schemaType.options.enum, null];
2965
+ }
2966
+ }
2967
+
2968
+ // Otherwise MongoDB errors with "$jsonSchema keyword 'required' cannot be an empty array"
2969
+ if (result.required.length === 0) {
2970
+ delete result.required;
2971
+ }
2972
+ return result;
2973
+ };
2974
+
2885
2975
  /*!
2886
2976
  * Module exports.
2887
2977
  */