mongoose 8.5.4 → 8.6.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.
- package/dist/browser.umd.js +1 -1
- package/lib/cursor/changeStream.js +31 -21
- package/lib/cursor/queryCursor.js +25 -0
- package/lib/document.js +3 -3
- package/lib/error/parallelSave.js +1 -1
- package/lib/error/parallelValidate.js +1 -1
- package/lib/error/version.js +1 -1
- package/lib/helpers/model/discriminator.js +3 -0
- package/lib/helpers/populate/getModelsMapForPopulate.js +2 -2
- package/lib/helpers/populate/markArraySubdocsPopulated.js +2 -2
- package/lib/model.js +9 -5
- package/lib/query.js +14 -7
- package/package.json +3 -3
- package/types/document.d.ts +5 -2
- package/types/inferrawdoctype.d.ts +4 -1
- package/types/inferschematype.d.ts +2 -2
- package/types/models.d.ts +37 -36
- package/types/query.d.ts +42 -28
|
@@ -33,15 +33,18 @@ class ChangeStream extends EventEmitter {
|
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
this.$driverChangeStreamPromise = new Promise((resolve, reject) => {
|
|
37
|
+
// This wrapper is necessary because of buffering.
|
|
38
|
+
changeStreamThunk((err, driverChangeStream) => {
|
|
39
|
+
if (err != null) {
|
|
40
|
+
this.emit('error', err);
|
|
41
|
+
return reject(err);
|
|
42
|
+
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
this.driverChangeStream = driverChangeStream;
|
|
45
|
+
this.emit('ready');
|
|
46
|
+
resolve();
|
|
47
|
+
});
|
|
45
48
|
});
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -53,20 +56,23 @@ class ChangeStream extends EventEmitter {
|
|
|
53
56
|
this.bindedEvents = true;
|
|
54
57
|
|
|
55
58
|
if (this.driverChangeStream == null) {
|
|
56
|
-
this.
|
|
57
|
-
|
|
58
|
-
this.
|
|
59
|
-
|
|
59
|
+
this.$driverChangeStreamPromise.then(
|
|
60
|
+
() => {
|
|
61
|
+
this.driverChangeStream.on('close', () => {
|
|
62
|
+
this.closed = true;
|
|
63
|
+
});
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
driverChangeStreamEvents.forEach(ev => {
|
|
66
|
+
this.driverChangeStream.on(ev, data => {
|
|
67
|
+
if (data != null && data.fullDocument != null && this.options && this.options.hydrate) {
|
|
68
|
+
data.fullDocument = this.options.model.hydrate(data.fullDocument);
|
|
69
|
+
}
|
|
70
|
+
this.emit(ev, data);
|
|
71
|
+
});
|
|
67
72
|
});
|
|
68
|
-
}
|
|
69
|
-
|
|
73
|
+
},
|
|
74
|
+
() => {} // No need to register events if opening change stream failed
|
|
75
|
+
);
|
|
70
76
|
|
|
71
77
|
return;
|
|
72
78
|
}
|
|
@@ -142,8 +148,12 @@ class ChangeStream extends EventEmitter {
|
|
|
142
148
|
this.closed = true;
|
|
143
149
|
if (this.driverChangeStream) {
|
|
144
150
|
return this.driverChangeStream.close();
|
|
151
|
+
} else {
|
|
152
|
+
return this.$driverChangeStreamPromise.then(
|
|
153
|
+
() => this.driverChangeStream.close(),
|
|
154
|
+
() => {} // No need to close if opening the change stream failed
|
|
155
|
+
);
|
|
145
156
|
}
|
|
146
|
-
return Promise.resolve();
|
|
147
157
|
}
|
|
148
158
|
}
|
|
149
159
|
|
|
@@ -10,6 +10,7 @@ const eachAsync = require('../helpers/cursor/eachAsync');
|
|
|
10
10
|
const helpers = require('../queryHelpers');
|
|
11
11
|
const kareem = require('kareem');
|
|
12
12
|
const immediate = require('../helpers/immediate');
|
|
13
|
+
const { once } = require('node:events');
|
|
13
14
|
const util = require('util');
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -42,6 +43,7 @@ function QueryCursor(query) {
|
|
|
42
43
|
this.cursor = null;
|
|
43
44
|
this.skipped = false;
|
|
44
45
|
this.query = query;
|
|
46
|
+
this._closed = false;
|
|
45
47
|
const model = query.model;
|
|
46
48
|
this._mongooseOptions = {};
|
|
47
49
|
this._transforms = [];
|
|
@@ -135,6 +137,25 @@ QueryCursor.prototype._read = function() {
|
|
|
135
137
|
});
|
|
136
138
|
};
|
|
137
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Returns the underlying cursor from the MongoDB Node driver that this cursor uses.
|
|
142
|
+
*
|
|
143
|
+
* @method getDriverCursor
|
|
144
|
+
* @memberOf QueryCursor
|
|
145
|
+
* @returns {Cursor} MongoDB Node driver cursor instance
|
|
146
|
+
* @instance
|
|
147
|
+
* @api public
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
QueryCursor.prototype.getDriverCursor = async function getDriverCursor() {
|
|
151
|
+
if (this.cursor) {
|
|
152
|
+
return this.cursor;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await once(this, 'cursor');
|
|
156
|
+
return this.cursor;
|
|
157
|
+
};
|
|
158
|
+
|
|
138
159
|
/**
|
|
139
160
|
* Registers a transform function which subsequently maps documents retrieved
|
|
140
161
|
* via the streams interface or `.next()`
|
|
@@ -209,6 +230,7 @@ QueryCursor.prototype.close = async function close() {
|
|
|
209
230
|
}
|
|
210
231
|
try {
|
|
211
232
|
await this.cursor.close();
|
|
233
|
+
this._closed = true;
|
|
212
234
|
this.emit('close');
|
|
213
235
|
} catch (error) {
|
|
214
236
|
this.listeners('error').length > 0 && this.emit('error', error);
|
|
@@ -246,6 +268,9 @@ QueryCursor.prototype.next = async function next() {
|
|
|
246
268
|
if (typeof arguments[0] === 'function') {
|
|
247
269
|
throw new MongooseError('QueryCursor.prototype.next() no longer accepts a callback');
|
|
248
270
|
}
|
|
271
|
+
if (this._closed) {
|
|
272
|
+
throw new MongooseError('Cannot call `next()` on a closed cursor');
|
|
273
|
+
}
|
|
249
274
|
return new Promise((resolve, reject) => {
|
|
250
275
|
_next(this, function(error, doc) {
|
|
251
276
|
if (error) {
|
package/lib/document.js
CHANGED
|
@@ -842,7 +842,7 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
842
842
|
*/
|
|
843
843
|
|
|
844
844
|
Document.prototype.updateOne = function updateOne(doc, options, callback) {
|
|
845
|
-
const query = this.constructor.updateOne({ _id: this._id }, doc, options);
|
|
845
|
+
const query = this.constructor.updateOne({ _id: this._doc._id }, doc, options);
|
|
846
846
|
const self = this;
|
|
847
847
|
query.pre(function queryPreUpdateOne(cb) {
|
|
848
848
|
self.constructor._middleware.execPre('updateOne', self, [self], cb);
|
|
@@ -883,7 +883,7 @@ Document.prototype.updateOne = function updateOne(doc, options, callback) {
|
|
|
883
883
|
|
|
884
884
|
Document.prototype.replaceOne = function replaceOne() {
|
|
885
885
|
const args = [...arguments];
|
|
886
|
-
args.unshift({ _id: this._id });
|
|
886
|
+
args.unshift({ _id: this._doc._id });
|
|
887
887
|
return this.constructor.replaceOne.apply(this.constructor, args);
|
|
888
888
|
};
|
|
889
889
|
|
|
@@ -3050,7 +3050,7 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
|
|
3050
3050
|
} else if (val != null && val.$__ != null && val.$__.wasPopulated) {
|
|
3051
3051
|
// Array paths, like `somearray.1`, do not show up as populated with `$populated()`,
|
|
3052
3052
|
// so in that case pull out the document's id
|
|
3053
|
-
val = val._id;
|
|
3053
|
+
val = val._doc._id;
|
|
3054
3054
|
}
|
|
3055
3055
|
const scope = _this.$__.pathsToScopes != null && path in _this.$__.pathsToScopes ?
|
|
3056
3056
|
_this.$__.pathsToScopes[path] :
|
package/lib/error/version.js
CHANGED
|
@@ -17,7 +17,7 @@ class VersionError extends MongooseError {
|
|
|
17
17
|
*/
|
|
18
18
|
constructor(doc, currentVersion, modifiedPaths) {
|
|
19
19
|
const modifiedPathsStr = modifiedPaths.join(', ');
|
|
20
|
-
super('No matching document found for id "' + doc._id +
|
|
20
|
+
super('No matching document found for id "' + doc._doc._id +
|
|
21
21
|
'" version ' + currentVersion + ' modifiedPaths "' + modifiedPathsStr + '"');
|
|
22
22
|
this.version = currentVersion;
|
|
23
23
|
this.modifiedPaths = modifiedPaths;
|
|
@@ -115,6 +115,9 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
// Shallow clone `obj` so we can add additional properties without modifying original
|
|
119
|
+
// schema. `Schema.prototype.clone()` copies `obj` by reference, no cloning.
|
|
120
|
+
schema.obj = { ...schema.obj };
|
|
118
121
|
mergeDiscriminatorSchema(schema, baseSchema);
|
|
119
122
|
|
|
120
123
|
// Clean up conflicting paths _after_ merging re: gh-6076
|
|
@@ -626,7 +626,7 @@ function _getLocalFieldValues(doc, localField, model, options, virtual, schema)
|
|
|
626
626
|
|
|
627
627
|
function convertTo_id(val, schema) {
|
|
628
628
|
if (val != null && val.$__ != null) {
|
|
629
|
-
return val._id;
|
|
629
|
+
return val._doc._id;
|
|
630
630
|
}
|
|
631
631
|
if (val != null && val._id != null && (schema == null || !schema.$isSchemaMap)) {
|
|
632
632
|
return val._id;
|
|
@@ -636,7 +636,7 @@ function convertTo_id(val, schema) {
|
|
|
636
636
|
const rawVal = val.__array != null ? val.__array : val;
|
|
637
637
|
for (let i = 0; i < rawVal.length; ++i) {
|
|
638
638
|
if (rawVal[i] != null && rawVal[i].$__ != null) {
|
|
639
|
-
rawVal[i] = rawVal[i]._id;
|
|
639
|
+
rawVal[i] = rawVal[i]._doc._id;
|
|
640
640
|
}
|
|
641
641
|
}
|
|
642
642
|
if (utils.isMongooseArray(val) && val.$schema()) {
|
|
@@ -17,11 +17,11 @@ const utils = require('../../utils');
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
module.exports = function markArraySubdocsPopulated(doc, populated) {
|
|
20
|
-
if (doc._id == null || populated == null || populated.length === 0) {
|
|
20
|
+
if (doc._doc._id == null || populated == null || populated.length === 0) {
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const id = String(doc._id);
|
|
24
|
+
const id = String(doc._doc._id);
|
|
25
25
|
for (const item of populated) {
|
|
26
26
|
if (item.isVirtual) {
|
|
27
27
|
continue;
|
package/lib/model.js
CHANGED
|
@@ -2115,17 +2115,21 @@ Model.countDocuments = function countDocuments(conditions, options) {
|
|
|
2115
2115
|
*
|
|
2116
2116
|
* @param {String} field
|
|
2117
2117
|
* @param {Object} [conditions] optional
|
|
2118
|
+
* @param {Object} [options] optional
|
|
2118
2119
|
* @return {Query}
|
|
2119
2120
|
* @api public
|
|
2120
2121
|
*/
|
|
2121
2122
|
|
|
2122
|
-
Model.distinct = function distinct(field, conditions) {
|
|
2123
|
+
Model.distinct = function distinct(field, conditions, options) {
|
|
2123
2124
|
_checkContext(this, 'distinct');
|
|
2124
|
-
if (typeof arguments[0] === 'function' || typeof arguments[1] === 'function') {
|
|
2125
|
+
if (typeof arguments[0] === 'function' || typeof arguments[1] === 'function' || typeof arguments[2] === 'function') {
|
|
2125
2126
|
throw new MongooseError('Model.distinct() no longer accepts a callback');
|
|
2126
2127
|
}
|
|
2127
2128
|
|
|
2128
2129
|
const mq = new this.Query({}, {}, this, this.$__collection);
|
|
2130
|
+
if (options != null) {
|
|
2131
|
+
mq.setOptions(options);
|
|
2132
|
+
}
|
|
2129
2133
|
|
|
2130
2134
|
return mq.distinct(field, conditions);
|
|
2131
2135
|
};
|
|
@@ -2345,7 +2349,7 @@ Model.findByIdAndUpdate = function(id, update, options) {
|
|
|
2345
2349
|
|
|
2346
2350
|
// if a model is passed in instead of an id
|
|
2347
2351
|
if (id instanceof Document) {
|
|
2348
|
-
id = id._id;
|
|
2352
|
+
id = id._doc._id;
|
|
2349
2353
|
}
|
|
2350
2354
|
|
|
2351
2355
|
return this.findOneAndUpdate.call(this, { _id: id }, update, options);
|
|
@@ -3408,7 +3412,7 @@ Model.bulkSave = async function bulkSave(documents, options) {
|
|
|
3408
3412
|
documents.map(async(document) => {
|
|
3409
3413
|
const documentError = bulkWriteError && bulkWriteError.writeErrors.find(writeError => {
|
|
3410
3414
|
const writeErrorDocumentId = writeError.err.op._id || writeError.err.op.q._id;
|
|
3411
|
-
return writeErrorDocumentId.toString() === document._id.toString();
|
|
3415
|
+
return writeErrorDocumentId.toString() === document._doc._id.toString();
|
|
3412
3416
|
});
|
|
3413
3417
|
|
|
3414
3418
|
if (documentError == null) {
|
|
@@ -4436,7 +4440,7 @@ function _assign(model, vals, mod, assignmentOpts) {
|
|
|
4436
4440
|
|
|
4437
4441
|
for (let __val of _val) {
|
|
4438
4442
|
if (__val instanceof Document) {
|
|
4439
|
-
__val = __val._id;
|
|
4443
|
+
__val = __val._doc._id;
|
|
4440
4444
|
}
|
|
4441
4445
|
key = String(__val);
|
|
4442
4446
|
if (rawDocs[key]) {
|
package/lib/query.js
CHANGED
|
@@ -2777,7 +2777,7 @@ Query.prototype.estimatedDocumentCount = function(options) {
|
|
|
2777
2777
|
this.op = 'estimatedDocumentCount';
|
|
2778
2778
|
this._validateOp();
|
|
2779
2779
|
|
|
2780
|
-
if (
|
|
2780
|
+
if (options != null) {
|
|
2781
2781
|
this.setOptions(options);
|
|
2782
2782
|
}
|
|
2783
2783
|
|
|
@@ -2836,7 +2836,7 @@ Query.prototype.countDocuments = function(conditions, options) {
|
|
|
2836
2836
|
this.merge(conditions);
|
|
2837
2837
|
}
|
|
2838
2838
|
|
|
2839
|
-
if (
|
|
2839
|
+
if (options != null) {
|
|
2840
2840
|
this.setOptions(options);
|
|
2841
2841
|
}
|
|
2842
2842
|
|
|
@@ -2874,21 +2874,24 @@ Query.prototype.__distinct = async function __distinct() {
|
|
|
2874
2874
|
*
|
|
2875
2875
|
* #### Example:
|
|
2876
2876
|
*
|
|
2877
|
+
* distinct(field, conditions, options)
|
|
2877
2878
|
* distinct(field, conditions)
|
|
2878
2879
|
* distinct(field)
|
|
2879
2880
|
* distinct()
|
|
2880
2881
|
*
|
|
2881
2882
|
* @param {String} [field]
|
|
2882
2883
|
* @param {Object|Query} [filter]
|
|
2884
|
+
* @param {Object} [options]
|
|
2883
2885
|
* @return {Query} this
|
|
2884
2886
|
* @see distinct https://www.mongodb.com/docs/manual/reference/method/db.collection.distinct/
|
|
2885
2887
|
* @api public
|
|
2886
2888
|
*/
|
|
2887
2889
|
|
|
2888
|
-
Query.prototype.distinct = function(field, conditions) {
|
|
2890
|
+
Query.prototype.distinct = function(field, conditions, options) {
|
|
2889
2891
|
if (typeof field === 'function' ||
|
|
2890
2892
|
typeof conditions === 'function' ||
|
|
2891
|
-
typeof
|
|
2893
|
+
typeof options === 'function' ||
|
|
2894
|
+
typeof arguments[3] === 'function') {
|
|
2892
2895
|
throw new MongooseError('Query.prototype.distinct() no longer accepts a callback');
|
|
2893
2896
|
}
|
|
2894
2897
|
|
|
@@ -2907,6 +2910,10 @@ Query.prototype.distinct = function(field, conditions) {
|
|
|
2907
2910
|
this._distinct = field;
|
|
2908
2911
|
}
|
|
2909
2912
|
|
|
2913
|
+
if (options != null) {
|
|
2914
|
+
this.setOptions(options);
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2910
2917
|
return this;
|
|
2911
2918
|
};
|
|
2912
2919
|
|
|
@@ -3380,9 +3387,9 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
|
|
|
3380
3387
|
if (!this._update || Object.keys(this._update).length === 0) {
|
|
3381
3388
|
if (options.upsert) {
|
|
3382
3389
|
// still need to do the upsert to empty doc
|
|
3383
|
-
const
|
|
3384
|
-
delete
|
|
3385
|
-
this._update = { $set
|
|
3390
|
+
const $set = clone(this._update);
|
|
3391
|
+
delete $set._id;
|
|
3392
|
+
this._update = { $set };
|
|
3386
3393
|
} else {
|
|
3387
3394
|
this._executionStack = null;
|
|
3388
3395
|
const res = await this._findOne();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongoose",
|
|
3
3
|
"description": "Mongoose MongoDB ODM",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.6.0",
|
|
5
5
|
"author": "Guillermo Rauch <guillermo@learnboost.com>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mongodb",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"bson": "^6.7.0",
|
|
23
23
|
"kareem": "2.6.3",
|
|
24
|
-
"mongodb": "6.
|
|
24
|
+
"mongodb": "6.8.0",
|
|
25
25
|
"mpath": "0.9.0",
|
|
26
26
|
"mquery": "5.0.0",
|
|
27
27
|
"ms": "2.1.3",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"tsd": "0.31.1",
|
|
68
68
|
"typescript": "5.5.4",
|
|
69
69
|
"uuid": "10.0.0",
|
|
70
|
-
"webpack": "5.
|
|
70
|
+
"webpack": "5.94.0"
|
|
71
71
|
},
|
|
72
72
|
"directories": {
|
|
73
73
|
"lib": "./lib/mongoose"
|
package/types/document.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ declare module 'mongoose' {
|
|
|
22
22
|
constructor(doc?: any);
|
|
23
23
|
|
|
24
24
|
/** This documents _id. */
|
|
25
|
-
_id
|
|
25
|
+
_id: T;
|
|
26
26
|
|
|
27
27
|
/** This documents __v. */
|
|
28
28
|
__v?: any;
|
|
@@ -259,11 +259,14 @@ declare module 'mongoose' {
|
|
|
259
259
|
set(value: string | Record<string, any>): this;
|
|
260
260
|
|
|
261
261
|
/** The return value of this method is used in calls to JSON.stringify(doc). */
|
|
262
|
+
toJSON(options?: ToObjectOptions & { flattenMaps?: true }): FlattenMaps<Require_id<DocType>>;
|
|
263
|
+
toJSON(options: ToObjectOptions & { flattenMaps: false }): Require_id<DocType>;
|
|
262
264
|
toJSON<T = Require_id<DocType>>(options?: ToObjectOptions & { flattenMaps?: true }): FlattenMaps<T>;
|
|
263
265
|
toJSON<T = Require_id<DocType>>(options: ToObjectOptions & { flattenMaps: false }): T;
|
|
264
266
|
|
|
265
267
|
/** Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)). */
|
|
266
|
-
toObject
|
|
268
|
+
toObject(options?: ToObjectOptions): Require_id<DocType>;
|
|
269
|
+
toObject<T>(options?: ToObjectOptions): Require_id<T>;
|
|
267
270
|
|
|
268
271
|
/** Clears the modified state on the specified path. */
|
|
269
272
|
unmarkModified<T extends keyof DocType>(path: T): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
IsPathRequired,
|
|
2
3
|
IsSchemaTypeFromBuiltinClass,
|
|
3
4
|
RequiredPaths,
|
|
4
5
|
OptionalPaths,
|
|
@@ -14,7 +15,9 @@ declare module 'mongoose' {
|
|
|
14
15
|
[
|
|
15
16
|
K in keyof (RequiredPaths<DocDefinition, TSchemaOptions['typeKey']> &
|
|
16
17
|
OptionalPaths<DocDefinition, TSchemaOptions['typeKey']>)
|
|
17
|
-
]:
|
|
18
|
+
]: IsPathRequired<DocDefinition[K], TSchemaOptions['typeKey']> extends true
|
|
19
|
+
? ObtainRawDocumentPathType<DocDefinition[K], TSchemaOptions['typeKey']>
|
|
20
|
+
: ObtainRawDocumentPathType<DocDefinition[K], TSchemaOptions['typeKey']> | null;
|
|
18
21
|
}, TSchemaOptions>;
|
|
19
22
|
|
|
20
23
|
/**
|
|
@@ -87,8 +87,8 @@ declare module 'mongoose' {
|
|
|
87
87
|
'createdAt' | 'updatedAt'
|
|
88
88
|
> as TimestampOptions[K] extends true
|
|
89
89
|
? K
|
|
90
|
-
: TimestampOptions[K] extends
|
|
91
|
-
?
|
|
90
|
+
: TimestampOptions[K] extends `${infer TimestampValue}`
|
|
91
|
+
? TimestampValue
|
|
92
92
|
: never]: NativeDate;
|
|
93
93
|
} & T
|
|
94
94
|
: T
|