mongoose 8.14.0 → 8.14.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.
@@ -81,6 +81,8 @@ function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, re
81
81
  if (id?.constructor?.name === 'Binary' && id.sub_type === 4 && typeof id.toUUID === 'function') {
82
82
  // Workaround for gh-15315 because Mongoose UUIDs don't use BSON UUIDs yet.
83
83
  sid = String(id.toUUID());
84
+ } else if (id?.constructor?.name === 'Buffer' && id._subtype === 4 && typeof id.toUUID === 'function') {
85
+ sid = String(id.toUUID());
84
86
  } else {
85
87
  sid = String(id);
86
88
  }
@@ -17,7 +17,7 @@ const updatedPathsByArrayFilter = require('../update/updatedPathsByArrayFilter')
17
17
  */
18
18
 
19
19
  module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, path, options) {
20
- const parts = path.split('.');
20
+ const parts = path.indexOf('.') === -1 ? [path] : path.split('.');
21
21
  let schematype = null;
22
22
  let type = 'adhocOrUndefined';
23
23
 
@@ -26,9 +26,10 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
26
26
  const arrayFilters = options != null && Array.isArray(options.arrayFilters) ?
27
27
  options.arrayFilters : [];
28
28
  const updatedPathsByFilter = updatedPathsByArrayFilter(update);
29
+ let startIndex = 0;
29
30
 
30
31
  for (let i = 0; i < parts.length; ++i) {
31
- const originalSubpath = parts.slice(0, i + 1).join('.');
32
+ const originalSubpath = parts.slice(startIndex, i + 1).join('.');
32
33
  const subpath = cleanPositionalOperators(originalSubpath);
33
34
  schematype = schema.path(subpath);
34
35
  if (schematype == null) {
@@ -89,6 +90,8 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
89
90
 
90
91
  const rest = parts.slice(i + 1).join('.');
91
92
  schematype = discriminatorSchema.path(rest);
93
+ schema = discriminatorSchema;
94
+ startIndex = i + 1;
92
95
  if (schematype != null) {
93
96
  type = discriminatorSchema._getPathType(rest);
94
97
  break;
@@ -8,7 +8,7 @@ const numberRE = /^\d+$/;
8
8
  * @api private
9
9
  */
10
10
 
11
- module.exports = function getPath(schema, path) {
11
+ module.exports = function getPath(schema, path, discriminatorValueMap) {
12
12
  let schematype = schema.path(path);
13
13
  if (schematype != null) {
14
14
  return schematype;
@@ -26,10 +26,13 @@ module.exports = function getPath(schema, path) {
26
26
  schematype = schema.path(cur);
27
27
  if (schematype != null && schematype.schema) {
28
28
  schema = schematype.schema;
29
- cur = '';
30
29
  if (!isArray && schematype.$isMongooseDocumentArray) {
31
30
  isArray = true;
32
31
  }
32
+ if (discriminatorValueMap && discriminatorValueMap[cur]) {
33
+ schema = schema.discriminators[discriminatorValueMap[cur]] ?? schema;
34
+ }
35
+ cur = '';
33
36
  }
34
37
  }
35
38
 
@@ -33,6 +33,10 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
33
33
  return;
34
34
  }
35
35
 
36
+ // Map to store discriminator values for embedded documents in the array filters.
37
+ // This is used to handle cases where array filters target specific embedded document types.
38
+ const discriminatorValueMap = {};
39
+
36
40
  for (const filter of arrayFilters) {
37
41
  if (filter == null) {
38
42
  throw new Error(`Got null array filter in ${arrayFilters}`);
@@ -58,12 +62,13 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
58
62
  updatedPathsByFilter[filterWildcardPath]
59
63
  );
60
64
 
61
- const baseSchematype = getPath(schema, baseFilterPath);
65
+ const baseSchematype = getPath(schema, baseFilterPath, discriminatorValueMap);
62
66
  let filterBaseSchema = baseSchematype != null ? baseSchematype.schema : null;
63
67
  if (filterBaseSchema != null &&
64
68
  filterBaseSchema.discriminators != null &&
65
69
  filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]) {
66
70
  filterBaseSchema = filterBaseSchema.discriminators[filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]] || filterBaseSchema;
71
+ discriminatorValueMap[baseFilterPath] = filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey];
67
72
  }
68
73
 
69
74
  for (const key of keys) {
@@ -83,7 +88,7 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
83
88
  // If there are multiple array filters in the path being updated, make sure
84
89
  // to replace them so we can get the schema path.
85
90
  filterPathRelativeToBase = cleanPositionalOperators(filterPathRelativeToBase);
86
- schematype = getPath(filterBaseSchema, filterPathRelativeToBase);
91
+ schematype = getPath(filterBaseSchema, filterPathRelativeToBase, discriminatorValueMap);
87
92
  }
88
93
 
89
94
  if (schematype == null) {
package/lib/model.js CHANGED
@@ -4688,7 +4688,14 @@ function _assign(model, vals, mod, assignmentOpts) {
4688
4688
  if (__val instanceof Document) {
4689
4689
  __val = __val._doc._id;
4690
4690
  }
4691
- key = String(__val);
4691
+ if (__val?.constructor?.name === 'Binary' && __val.sub_type === 4 && typeof __val.toUUID === 'function') {
4692
+ // Workaround for gh-15315 because Mongoose UUIDs don't use BSON UUIDs yet.
4693
+ key = String(__val.toUUID());
4694
+ } else if (__val?.constructor?.name === 'Buffer' && __val._subtype === 4 && typeof __val.toUUID === 'function') {
4695
+ key = String(__val.toUUID());
4696
+ } else {
4697
+ key = String(__val);
4698
+ }
4692
4699
  if (rawDocs[key]) {
4693
4700
  if (Array.isArray(rawDocs[key])) {
4694
4701
  rawDocs[key].push(val);
@@ -4711,7 +4718,14 @@ function _assign(model, vals, mod, assignmentOpts) {
4711
4718
  if (_val instanceof Document) {
4712
4719
  _val = _val._doc._id;
4713
4720
  }
4714
- key = String(_val);
4721
+ if (_val?.constructor?.name === 'Binary' && _val.sub_type === 4 && typeof _val.toUUID === 'function') {
4722
+ // Workaround for gh-15315 because Mongoose UUIDs don't use BSON UUIDs yet.
4723
+ key = String(_val.toUUID());
4724
+ } else if (_val?.constructor?.name === 'Buffer' && _val._subtype === 4 && typeof _val.toUUID === 'function') {
4725
+ key = String(_val.toUUID());
4726
+ } else {
4727
+ key = String(_val);
4728
+ }
4715
4729
  if (rawDocs[key]) {
4716
4730
  if (Array.isArray(rawDocs[key])) {
4717
4731
  rawDocs[key].push(val);
package/lib/schema/map.js CHANGED
@@ -23,12 +23,12 @@ class SchemaMap extends SchemaType {
23
23
  return SchemaType.set(option, value);
24
24
  }
25
25
 
26
- cast(val, doc, init) {
26
+ cast(val, doc, init, prev, options) {
27
27
  if (val instanceof MongooseMap) {
28
28
  return val;
29
29
  }
30
30
 
31
- const path = this.path;
31
+ const path = options?.path ?? this.path;
32
32
 
33
33
  if (init) {
34
34
  const map = new MongooseMap({}, path, doc, this.$__schemaType);
package/lib/schema.js CHANGED
@@ -77,7 +77,7 @@ const numberRE = /^\d+$/;
77
77
  * - [validateBeforeSave](https://mongoosejs.com/docs/guide.html#validateBeforeSave) - bool - defaults to `true`
78
78
  * - [validateModifiedOnly](https://mongoosejs.com/docs/api/document.html#Document.prototype.validate()) - bool - defaults to `false`
79
79
  * - [versionKey](https://mongoosejs.com/docs/guide.html#versionKey): string or object - defaults to "__v"
80
- * - [optimisticConcurrency](https://mongoosejs.com/docs/guide.html#optimisticConcurrency): bool - defaults to false. Set to true to enable [optimistic concurrency](https://thecodebarbarian.com/whats-new-in-mongoose-5-10-optimistic-concurrency.html).
80
+ * - [optimisticConcurrency](https://mongoosejs.com/docs/guide.html#optimisticConcurrency): bool or string[] or { exclude: string[] } - defaults to false. Set to true to enable [optimistic concurrency](https://thecodebarbarian.com/whats-new-in-mongoose-5-10-optimistic-concurrency.html). Set to string array to enable optimistic concurrency for only certain fields, or `{ exclude: string[] }` to define a list of fields to ignore for optimistic concurrency.
81
81
  * - [collation](https://mongoosejs.com/docs/guide.html#collation): object - defaults to null (which means use no collation)
82
82
  * - [timeseries](https://mongoosejs.com/docs/guide.html#timeseries): object - defaults to null (which means this schema's collection won't be a timeseries collection)
83
83
  * - [selectPopulatedPaths](https://mongoosejs.com/docs/guide.html#selectPopulatedPaths): boolean - defaults to `true`
@@ -5,6 +5,7 @@
5
5
  'use strict';
6
6
 
7
7
  const Binary = require('bson').Binary;
8
+ const UUID = require('bson').UUID;
8
9
  const utils = require('../utils');
9
10
 
10
11
  /**
@@ -207,6 +208,22 @@ MongooseBuffer.mixin.toBSON = function() {
207
208
  return new Binary(this, this._subtype || 0);
208
209
  };
209
210
 
211
+ /**
212
+ * Converts this buffer to a UUID. Throws an error if subtype is not 4.
213
+ *
214
+ * @return {UUID}
215
+ * @api public
216
+ * @method toUUID
217
+ * @memberOf MongooseBuffer
218
+ */
219
+
220
+ MongooseBuffer.mixin.toUUID = function() {
221
+ if (this._subtype !== 4) {
222
+ throw new Error('Cannot convert a Buffer with subtype ' + this._subtype + ' to a UUID');
223
+ }
224
+ return new UUID(this);
225
+ };
226
+
210
227
  /**
211
228
  * Determines if this buffer is equals to `other` buffer
212
229
  *
package/lib/types/map.js CHANGED
@@ -136,7 +136,7 @@ class MongooseMap extends Map {
136
136
  }
137
137
  } else {
138
138
  try {
139
- const options = this.$__schemaType.$isMongooseDocumentArray || this.$__schemaType.$isSingleNested ?
139
+ const options = this.$__schemaType.$isMongooseDocumentArray || this.$__schemaType.$isSingleNested || this.$__schemaType.$isMongooseArray || this.$__schemaType.$isSchemaMap ?
140
140
  { path: fullPath.call(this) } :
141
141
  null;
142
142
  value = this.$__schemaType.applySetters(
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "8.14.0",
4
+ "version": "8.14.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -29,8 +29,8 @@
29
29
  "sift": "17.1.3"
30
30
  },
31
31
  "devDependencies": {
32
- "@babel/core": "7.26.10",
33
- "@babel/preset-env": "7.26.9",
32
+ "@babel/core": "7.27.1",
33
+ "@babel/preset-env": "7.27.1",
34
34
  "@typescript-eslint/eslint-plugin": "^8.19.1",
35
35
  "@typescript-eslint/parser": "^8.19.1",
36
36
  "acquit": "1.3.0",
@@ -53,9 +53,9 @@
53
53
  "lodash.isequal": "4.5.0",
54
54
  "lodash.isequalwith": "4.4.0",
55
55
  "markdownlint-cli2": "^0.17.1",
56
- "marked": "15.0.7",
56
+ "marked": "15.0.11",
57
57
  "mkdirp": "^3.0.1",
58
- "mocha": "11.1.0",
58
+ "mocha": "11.2.2",
59
59
  "moment": "2.30.1",
60
60
  "mongodb-memory-server": "10.1.4",
61
61
  "ncp": "^2.0.0",
@@ -64,10 +64,10 @@
64
64
  "q": "1.5.1",
65
65
  "sinon": "20.0.0",
66
66
  "stream-browserify": "3.0.0",
67
- "tsd": "0.31.2",
68
- "typescript": "5.7.3",
67
+ "tsd": "0.32.0",
68
+ "typescript": "5.8.3",
69
69
  "uuid": "11.1.0",
70
- "webpack": "5.98.0"
70
+ "webpack": "5.99.7"
71
71
  },
72
72
  "directories": {
73
73
  "lib": "./lib/mongoose"
@@ -101,7 +101,7 @@
101
101
  "mongo": "node ./tools/repl.js",
102
102
  "publish-7x": "npm publish --tag 7x",
103
103
  "test": "mocha --exit ./test/*.test.js",
104
- "test-deno": "deno run --allow-env --allow-read --allow-net --allow-run --allow-sys --allow-write ./test/deno.js",
104
+ "test-deno": "deno run --allow-env --allow-read --allow-net --allow-run --allow-sys --allow-write ./test/deno.mjs",
105
105
  "test-rs": "START_REPLICA_SET=1 mocha --timeout 30000 --exit ./test/*.test.js",
106
106
  "test-tsd": "node ./test/types/check-types-filename && tsd",
107
107
  "setup-test-encryption": "bash scripts/configure-cluster-with-encryption.sh",
@@ -107,9 +107,10 @@ declare module 'mongoose' {
107
107
  /**
108
108
  * Optimistic concurrency is a strategy to ensure the document you're updating didn't change between when you
109
109
  * loaded it using find() or findOne(), and when you update it using save(). Set to `true` to enable
110
- * optimistic concurrency.
110
+ * optimistic concurrency. Set to string array to enable optimistic concurrency for only certain fields,
111
+ * or `{ exclude: string[] }` to define a list of fields to ignore for optimistic concurrency.
111
112
  */
112
- optimisticConcurrency?: boolean;
113
+ optimisticConcurrency?: boolean | string[] | { exclude: string[] };
113
114
  /**
114
115
  * If `plugin()` called with tags, Mongoose will only apply plugins to schemas that have
115
116
  * a matching tag in `pluginTags`