mongoose 8.9.1 → 8.9.2

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/aggregate.js CHANGED
@@ -87,6 +87,24 @@ function Aggregate(pipeline, model) {
87
87
 
88
88
  Aggregate.prototype.options;
89
89
 
90
+ /**
91
+ * Returns default options for this aggregate.
92
+ *
93
+ * @param {Model} model
94
+ * @api private
95
+ */
96
+
97
+ Aggregate.prototype._optionsForExec = function() {
98
+ const options = this.options || {};
99
+
100
+ const asyncLocalStorage = this.model()?.db?.base.transactionAsyncLocalStorage?.getStore();
101
+ if (!options.hasOwnProperty('session') && asyncLocalStorage?.session != null) {
102
+ options.session = asyncLocalStorage.session;
103
+ }
104
+
105
+ return options;
106
+ };
107
+
90
108
  /**
91
109
  * Get/set the model that this aggregation will execute on.
92
110
  *
@@ -914,6 +932,7 @@ Aggregate.prototype.option = function(value) {
914
932
  */
915
933
 
916
934
  Aggregate.prototype.cursor = function(options) {
935
+ this._optionsForExec();
917
936
  this.options.cursor = options || {};
918
937
  return new AggregationCursor(this); // return this;
919
938
  };
@@ -1022,10 +1041,7 @@ Aggregate.prototype.exec = async function exec() {
1022
1041
  applyGlobalMaxTimeMS(this.options, model.db.options, model.base.options);
1023
1042
  applyGlobalDiskUse(this.options, model.db.options, model.base.options);
1024
1043
 
1025
- const asyncLocalStorage = this.model()?.db?.base.transactionAsyncLocalStorage?.getStore();
1026
- if (!this.options.hasOwnProperty('session') && asyncLocalStorage?.session != null) {
1027
- this.options.session = asyncLocalStorage.session;
1028
- }
1044
+ this._optionsForExec();
1029
1045
 
1030
1046
  if (this.options && this.options.cursor) {
1031
1047
  return new AggregationCursor(this);
@@ -1052,6 +1068,7 @@ Aggregate.prototype.exec = async function exec() {
1052
1068
  }
1053
1069
 
1054
1070
  const options = clone(this.options || {});
1071
+
1055
1072
  let result;
1056
1073
  try {
1057
1074
  const cursor = await collection.aggregate(this._pipeline, options);
package/lib/connection.js CHANGED
@@ -663,7 +663,7 @@ Connection.prototype.withSession = async function withSession(executor) {
663
663
  *
664
664
  * const session = await conn.startSession();
665
665
  * let doc = await Person.findOne({ name: 'Ned Stark' }, null, { session });
666
- * await doc.remove();
666
+ * await doc.deleteOne();
667
667
  * // `doc` will always be null, even if reading from a replica set
668
668
  * // secondary. Without causal consistency, it is possible to
669
669
  * // get a doc back from the below query if the query reads from a
package/lib/document.js CHANGED
@@ -2357,17 +2357,17 @@ Document.prototype.$isDefault = function(path) {
2357
2357
  };
2358
2358
 
2359
2359
  /**
2360
- * Getter/setter, determines whether the document was removed or not.
2360
+ * Getter/setter, determines whether the document was deleted. The `Model.prototype.deleteOne()` method sets `$isDeleted` if the delete operation succeeded.
2361
2361
  *
2362
2362
  * #### Example:
2363
2363
  *
2364
- * const product = await product.remove();
2364
+ * const product = await product.deleteOne();
2365
2365
  * product.$isDeleted(); // true
2366
- * product.remove(); // no-op, doesn't send anything to the db
2366
+ * product.deleteOne(); // no-op, doesn't send anything to the db
2367
2367
  *
2368
2368
  * product.$isDeleted(false);
2369
2369
  * product.$isDeleted(); // false
2370
- * product.remove(); // will execute a remove against the db
2370
+ * product.deleteOne(); // will execute a remove against the db
2371
2371
  *
2372
2372
  *
2373
2373
  * @param {Boolean} [val] optional, overrides whether mongoose thinks the doc is deleted
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Compares two index specifications to determine if they are equal.
5
+ *
6
+ * #### Example:
7
+ * isIndexSpecEqual({ a: 1, b: 1 }, { a: 1, b: 1 }); // true
8
+ * isIndexSpecEqual({ a: 1, b: 1 }, { b: 1, a: 1 }); // false
9
+ * isIndexSpecEqual({ a: 1, b: -1 }, { a: 1, b: 1 }); // false
10
+ *
11
+ * @param {Object} spec1 The first index specification to compare.
12
+ * @param {Object} spec2 The second index specification to compare.
13
+ * @returns {Boolean} Returns true if the index specifications are equal, otherwise returns false.
14
+ */
15
+
16
+ module.exports = function isIndexSpecEqual(spec1, spec2) {
17
+ const spec1Keys = Object.keys(spec1);
18
+ const spec2Keys = Object.keys(spec2);
19
+
20
+ if (spec1Keys.length !== spec2Keys.length) {
21
+ return false;
22
+ }
23
+
24
+ for (let i = 0; i < spec1Keys.length; i++) {
25
+ const key = spec1Keys[i];
26
+ if (key !== spec2Keys[i] || spec1[key] !== spec2[key]) {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ return true;
32
+ };
package/lib/model.js CHANGED
@@ -694,13 +694,20 @@ Model.prototype.$__where = function _where(where) {
694
694
  };
695
695
 
696
696
  /**
697
- * Delete this document from the db.
697
+ * Delete this document from the db. Returns a Query instance containing a `deleteOne` operation by this document's `_id`.
698
698
  *
699
699
  * #### Example:
700
700
  *
701
701
  * await product.deleteOne();
702
702
  * await Product.findById(product._id); // null
703
703
  *
704
+ * Since `deleteOne()` returns a Query, the `deleteOne()` will **not** execute unless you use either `await`, `.then()`, `.catch()`, or [`.exec()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.exec())
705
+ *
706
+ * #### Example:
707
+ *
708
+ * product.deleteOne(); // Doesn't do anything
709
+ * product.deleteOne().exec(); // Deletes the document, returns a promise
710
+ *
704
711
  * @return {Query} Query
705
712
  * @api public
706
713
  */
@@ -1879,8 +1886,6 @@ Model.translateAliases = function translateAliases(fields, errorOnDuplicates) {
1879
1886
  /**
1880
1887
  * Deletes the first document that matches `conditions` from the collection.
1881
1888
  * It returns an object with the property `deletedCount` indicating how many documents were deleted.
1882
- * Behaves like `remove()`, but deletes at most one document regardless of the
1883
- * `single` option.
1884
1889
  *
1885
1890
  * #### Example:
1886
1891
  *
@@ -1914,8 +1919,6 @@ Model.deleteOne = function deleteOne(conditions, options) {
1914
1919
  /**
1915
1920
  * Deletes all of the documents that match `conditions` from the collection.
1916
1921
  * It returns an object with the property `deletedCount` containing the number of documents deleted.
1917
- * Behaves like `remove()`, but deletes all documents that match `conditions`
1918
- * regardless of the `single` option.
1919
1922
  *
1920
1923
  * #### Example:
1921
1924
  *
@@ -2729,7 +2732,7 @@ Model.create = async function create(doc, options) {
2729
2732
  * // operationType: 'delete',
2730
2733
  * // ns: { db: 'mydb', coll: 'Person' },
2731
2734
  * // documentKey: { _id: 5a51b125c5500f5aa094c7bd } }
2732
- * await doc.remove();
2735
+ * await doc.deleteOne();
2733
2736
  *
2734
2737
  * @param {Array} [pipeline]
2735
2738
  * @param {Object} [options] see the [mongodb driver options](https://mongodb.github.io/node-mongodb-native/4.9/classes/Collection.html#watch)
@@ -2777,7 +2780,7 @@ Model.watch = function(pipeline, options) {
2777
2780
  *
2778
2781
  * const session = await Person.startSession();
2779
2782
  * let doc = await Person.findOne({ name: 'Ned Stark' }, null, { session });
2780
- * await doc.remove();
2783
+ * await doc.deleteOne();
2781
2784
  * // `doc` will always be null, even if reading from a replica set
2782
2785
  * // secondary. Without causal consistency, it is possible to
2783
2786
  * // get a doc back from the below query if the query reads from a
package/lib/query.js CHANGED
@@ -2247,10 +2247,7 @@ Query.prototype.error = function error(err) {
2247
2247
  */
2248
2248
 
2249
2249
  Query.prototype._unsetCastError = function _unsetCastError() {
2250
- if (this._error == null) {
2251
- return;
2252
- }
2253
- if (this._error != null && !(this._error instanceof CastError)) {
2250
+ if (this._error == null || !(this._error instanceof CastError)) {
2254
2251
  return;
2255
2252
  }
2256
2253
  return this.error(null);
package/lib/schema.js CHANGED
@@ -18,13 +18,13 @@ const getConstructorName = require('./helpers/getConstructorName');
18
18
  const getIndexes = require('./helpers/schema/getIndexes');
19
19
  const handleReadPreferenceAliases = require('./helpers/query/handleReadPreferenceAliases');
20
20
  const idGetter = require('./helpers/schema/idGetter');
21
+ const isIndexSpecEqual = require('./helpers/indexes/isIndexSpecEqual');
21
22
  const merge = require('./helpers/schema/merge');
22
23
  const mpath = require('mpath');
23
24
  const setPopulatedVirtualValue = require('./helpers/populate/setPopulatedVirtualValue');
24
25
  const setupTimestamps = require('./helpers/timestamps/setupTimestamps');
25
26
  const utils = require('./utils');
26
27
  const validateRef = require('./helpers/populate/validateRef');
27
- const util = require('util');
28
28
 
29
29
  const hasNumericSubpathRegex = /\.\d+(\.|$)/;
30
30
 
@@ -899,7 +899,7 @@ Schema.prototype.removeIndex = function removeIndex(index) {
899
899
 
900
900
  if (typeof index === 'object') {
901
901
  for (let i = this._indexes.length - 1; i >= 0; --i) {
902
- if (util.isDeepStrictEqual(this._indexes[i][0], index)) {
902
+ if (isIndexSpecEqual(this._indexes[i][0], index)) {
903
903
  this._indexes.splice(i, 1);
904
904
  }
905
905
  }
@@ -2147,7 +2147,7 @@ Schema.prototype.index = function(fields, options) {
2147
2147
  }
2148
2148
 
2149
2149
  for (const existingIndex of this.indexes()) {
2150
- if (util.isDeepStrictEqual(existingIndex[0], fields)) {
2150
+ if (options.name == null && existingIndex[1].name == null && isIndexSpecEqual(existingIndex[0], fields)) {
2151
2151
  throw new MongooseError(`Schema already has an index on ${JSON.stringify(fields)}`);
2152
2152
  }
2153
2153
  }
package/lib/types/map.js CHANGED
@@ -9,6 +9,7 @@ const handleSpreadDoc = require('../helpers/document/handleSpreadDoc');
9
9
  const util = require('util');
10
10
  const specialProperties = require('../helpers/specialProperties');
11
11
  const isBsonType = require('../helpers/isBsonType');
12
+ const cleanModifiedSubpaths = require('../helpers/document/cleanModifiedSubpaths');
12
13
 
13
14
  const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
14
15
 
@@ -157,7 +158,13 @@ class MongooseMap extends Map {
157
158
  super.set(key, value);
158
159
 
159
160
  if (parent != null && parent.$__ != null && !deepEqual(value, priorVal)) {
160
- parent.markModified(fullPath.call(this));
161
+ const path = fullPath.call(this);
162
+ parent.markModified(path);
163
+ // If overwriting the full document array or subdoc, make sure to clean up any paths that were modified
164
+ // before re: #15108
165
+ if (this.$__schemaType.$isMongooseDocumentArray || this.$__schemaType.$isSingleNested) {
166
+ cleanModifiedSubpaths(parent, path);
167
+ }
161
168
  }
162
169
 
163
170
  // Delay calculating full path unless absolutely necessary, because string
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "8.9.1",
4
+ "version": "8.9.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
package/types/index.d.ts CHANGED
@@ -572,7 +572,8 @@ declare module 'mongoose' {
572
572
  | typeof Schema.Types.Number
573
573
  | typeof Schema.Types.String
574
574
  | typeof Schema.Types.Buffer
575
- | typeof Schema.Types.ObjectId;
575
+ | typeof Schema.Types.ObjectId
576
+ | typeof Schema.Types.UUID;
576
577
 
577
578
 
578
579
  export type InferId<T> = T extends { _id?: any } ? T['_id'] : Types.ObjectId;
@@ -712,76 +713,82 @@ declare module 'mongoose' {
712
713
  /**
713
714
  * Converts any Buffer properties into mongodb.Binary instances, which is what `lean()` returns
714
715
  */
715
- export type BufferToBinary<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
716
- [K in keyof T]: T[K] extends Buffer
717
- ? mongodb.Binary
718
- : T[K] extends (Buffer | null | undefined)
719
- ? mongodb.Binary | null | undefined
720
- : T[K] extends Types.DocumentArray<infer ItemType>
716
+ export type BufferToBinary<T> = T extends Buffer
717
+ ? mongodb.Binary
718
+ : T extends TreatAsPrimitives
719
+ ? T
720
+ : T extends Record<string, any> ? {
721
+ [K in keyof T]: T[K] extends Buffer
722
+ ? mongodb.Binary
723
+ : T[K] extends Types.DocumentArray<infer ItemType>
721
724
  ? Types.DocumentArray<BufferToBinary<ItemType>>
722
725
  : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
723
726
  ? HydratedSingleSubdocument<SubdocType>
724
727
  : BufferToBinary<T[K]>;
725
- } : T;
728
+ } : T;
726
729
 
727
730
  /**
728
731
  * Converts any Buffer properties into { type: 'buffer', data: [1, 2, 3] } format for JSON serialization
729
732
  */
730
- export type BufferToJSON<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
731
- [K in keyof T]: T[K] extends Buffer
732
- ? { type: 'buffer', data: number[] }
733
- : T[K] extends (Buffer | null | undefined)
734
- ? { type: 'buffer', data: number[] } | null | undefined
735
- : T[K] extends Types.DocumentArray<infer ItemType>
736
- ? Types.DocumentArray<BufferToBinary<ItemType>>
737
- : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
738
- ? HydratedSingleSubdocument<SubdocType>
739
- : BufferToBinary<T[K]>;
740
- } : T;
733
+ export type BufferToJSON<T> = T extends Buffer
734
+ ? { type: 'buffer', data: number[] }
735
+ : T extends TreatAsPrimitives
736
+ ? T
737
+ : T extends Record<string, any> ? {
738
+ [K in keyof T]: T[K] extends Buffer
739
+ ? { type: 'buffer', data: number[] }
740
+ : T[K] extends Types.DocumentArray<infer ItemType>
741
+ ? Types.DocumentArray<BufferToBinary<ItemType>>
742
+ : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
743
+ ? HydratedSingleSubdocument<SubdocType>
744
+ : BufferToBinary<T[K]>;
745
+ } : T;
741
746
 
742
747
  /**
743
748
  * Converts any ObjectId properties into strings for JSON serialization
744
749
  */
745
- export type ObjectIdToString<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
746
- [K in keyof T]: T[K] extends mongodb.ObjectId
747
- ? string
748
- : T[K] extends (mongodb.ObjectId | null | undefined)
749
- ? string | null | undefined
750
- : T[K] extends Types.DocumentArray<infer ItemType>
751
- ? Types.DocumentArray<ObjectIdToString<ItemType>>
752
- : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
753
- ? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
754
- : ObjectIdToString<T[K]>;
755
- } : T;
750
+ export type ObjectIdToString<T> = T extends mongodb.ObjectId
751
+ ? string
752
+ : T extends TreatAsPrimitives
753
+ ? T
754
+ : T extends Record<string, any> ? {
755
+ [K in keyof T]: T[K] extends mongodb.ObjectId
756
+ ? string
757
+ : T[K] extends Types.DocumentArray<infer ItemType>
758
+ ? Types.DocumentArray<ObjectIdToString<ItemType>>
759
+ : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
760
+ ? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
761
+ : ObjectIdToString<T[K]>;
762
+ } : T;
756
763
 
757
764
  /**
758
765
  * Converts any Date properties into strings for JSON serialization
759
766
  */
760
- export type DateToString<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
761
- [K in keyof T]: T[K] extends NativeDate
762
- ? string
763
- : T[K] extends (NativeDate | null | undefined)
764
- ? string | null | undefined
765
- : T[K] extends Types.DocumentArray<infer ItemType>
766
- ? Types.DocumentArray<DateToString<ItemType>>
767
- : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
768
- ? HydratedSingleSubdocument<DateToString<SubdocType>>
769
- : DateToString<T[K]>;
770
- } : T;
767
+ export type DateToString<T> = T extends NativeDate
768
+ ? string
769
+ : T extends TreatAsPrimitives
770
+ ? T
771
+ : T extends Record<string, any> ? {
772
+ [K in keyof T]: T[K] extends NativeDate
773
+ ? string
774
+ : T[K] extends (NativeDate | null | undefined)
775
+ ? string | null | undefined
776
+ : T[K] extends Types.DocumentArray<infer ItemType>
777
+ ? Types.DocumentArray<DateToString<ItemType>>
778
+ : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
779
+ ? HydratedSingleSubdocument<DateToString<SubdocType>>
780
+ : DateToString<T[K]>;
781
+ } : T;
771
782
 
772
783
  /**
773
784
  * Converts any Mongoose subdocuments (single nested or doc arrays) into POJO equivalents
774
785
  */
775
786
  export type SubdocsToPOJOs<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
776
- [K in keyof T]: T[K] extends NativeDate
777
- ? string
778
- : T[K] extends (NativeDate | null | undefined)
779
- ? string | null | undefined
780
- : T[K] extends Types.DocumentArray<infer ItemType>
781
- ? ItemType[]
782
- : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
783
- ? SubdocType
784
- : SubdocsToPOJOs<T[K]>;
787
+ [K in keyof T]: T[K] extends Types.DocumentArray<infer ItemType>
788
+ ? ItemType[]
789
+ : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
790
+ ? SubdocType
791
+ : SubdocsToPOJOs<T[K]>;
785
792
  } : T;
786
793
 
787
794
  export type JSONSerialized<T> = SubdocsToPOJOs<