mongoose 7.3.4 → 7.4.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/cast.js +2 -2
- package/lib/connection.js +32 -200
- package/lib/document.js +30 -34
- package/lib/drivers/node-mongodb-native/connection.js +247 -0
- package/lib/error/cast.js +10 -9
- package/lib/error/messages.js +1 -1
- package/lib/helpers/schema/getPath.js +0 -1
- package/lib/helpers/schema/idGetter.js +12 -1
- package/lib/model.js +45 -16
- package/lib/query.js +36 -21
- package/lib/schema/SubdocumentPath.js +10 -4
- package/lib/schema/array.js +2 -0
- package/lib/schema/bigint.js +2 -0
- package/lib/schema/boolean.js +2 -0
- package/lib/schema/buffer.js +2 -0
- package/lib/schema/date.js +2 -0
- package/lib/schema/decimal128.js +2 -0
- package/lib/schema/documentarray.js +2 -0
- package/lib/schema/mixed.js +2 -0
- package/lib/schema/number.js +2 -0
- package/lib/schema/objectid.js +2 -0
- package/lib/schema/string.js +2 -0
- package/lib/schema/uuid.js +2 -0
- package/lib/schema.js +5 -3
- package/lib/schematype.js +20 -4
- package/package.json +3 -3
- package/types/augmentations.d.ts +9 -0
- package/types/index.d.ts +1 -0
- package/types/models.d.ts +7 -2
- package/types/query.d.ts +1 -1
- package/types/schemaoptions.d.ts +3 -0
- package/types/schematypes.d.ts +5 -1
- package/types/types.d.ts +0 -1
- package/lib/helpers/path/flattenObjectWithDottedPaths.js +0 -39
|
@@ -5,8 +5,13 @@
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
7
|
const MongooseConnection = require('../../connection');
|
|
8
|
+
const MongooseError = require('../../error/index');
|
|
8
9
|
const STATES = require('../../connectionstate');
|
|
10
|
+
const mongodb = require('mongodb');
|
|
11
|
+
const pkg = require('../../../package.json');
|
|
12
|
+
const processConnectionOptions = require('../../helpers/processConnectionOptions');
|
|
9
13
|
const setTimeout = require('../../helpers/timers').setTimeout;
|
|
14
|
+
const utils = require('../../utils');
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) connection implementation.
|
|
@@ -121,6 +126,44 @@ NativeConnection.prototype.useDb = function(name, options) {
|
|
|
121
126
|
return newConn;
|
|
122
127
|
};
|
|
123
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Removes the database connection with the given name created with `useDb()`.
|
|
131
|
+
*
|
|
132
|
+
* Throws an error if the database connection was not found.
|
|
133
|
+
*
|
|
134
|
+
* #### Example:
|
|
135
|
+
*
|
|
136
|
+
* // Connect to `initialdb` first
|
|
137
|
+
* const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/initialdb').asPromise();
|
|
138
|
+
*
|
|
139
|
+
* // Creates an un-cached connection to `mydb`
|
|
140
|
+
* const db = conn.useDb('mydb');
|
|
141
|
+
*
|
|
142
|
+
* // Closes `db`, and removes `db` from `conn.relatedDbs` and `conn.otherDbs`
|
|
143
|
+
* await conn.removeDb('mydb');
|
|
144
|
+
*
|
|
145
|
+
* @method removeDb
|
|
146
|
+
* @memberOf Connection
|
|
147
|
+
* @param {String} name The database name
|
|
148
|
+
* @return {Connection} this
|
|
149
|
+
*/
|
|
150
|
+
|
|
151
|
+
NativeConnection.prototype.removeDb = function removeDb(name) {
|
|
152
|
+
const dbs = this.otherDbs.filter(db => db.name === name);
|
|
153
|
+
if (!dbs.length) {
|
|
154
|
+
throw new MongooseError(`No connections to database "${name}" found`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
for (const db of dbs) {
|
|
158
|
+
db._closeCalled = true;
|
|
159
|
+
db._destroyCalled = true;
|
|
160
|
+
db._readyState = STATES.disconnected;
|
|
161
|
+
db.$wasForceClosed = true;
|
|
162
|
+
}
|
|
163
|
+
delete this.relatedDbs[name];
|
|
164
|
+
this.otherDbs = this.otherDbs.filter(db => db.name !== name);
|
|
165
|
+
};
|
|
166
|
+
|
|
124
167
|
/**
|
|
125
168
|
* Closes the connection
|
|
126
169
|
*
|
|
@@ -154,6 +197,210 @@ NativeConnection.prototype.doClose = async function doClose(force) {
|
|
|
154
197
|
return this;
|
|
155
198
|
};
|
|
156
199
|
|
|
200
|
+
/*!
|
|
201
|
+
* ignore
|
|
202
|
+
*/
|
|
203
|
+
|
|
204
|
+
NativeConnection.prototype.createClient = async function createClient(uri, options) {
|
|
205
|
+
if (typeof uri !== 'string') {
|
|
206
|
+
throw new MongooseError('The `uri` parameter to `openUri()` must be a ' +
|
|
207
|
+
`string, got "${typeof uri}". Make sure the first parameter to ` +
|
|
208
|
+
'`mongoose.connect()` or `mongoose.createConnection()` is a string.');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (this._destroyCalled) {
|
|
212
|
+
throw new MongooseError(
|
|
213
|
+
'Connection has been closed and destroyed, and cannot be used for re-opening the connection. ' +
|
|
214
|
+
'Please create a new connection with `mongoose.createConnection()` or `mongoose.connect()`.'
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (this.readyState === STATES.connecting || this.readyState === STATES.connected) {
|
|
219
|
+
if (this._connectionString !== uri) {
|
|
220
|
+
throw new MongooseError('Can\'t call `openUri()` on an active connection with ' +
|
|
221
|
+
'different connection strings. Make sure you aren\'t calling `mongoose.connect()` ' +
|
|
222
|
+
'multiple times. See: https://mongoosejs.com/docs/connections.html#multiple_connections');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
options = processConnectionOptions(uri, options);
|
|
227
|
+
|
|
228
|
+
if (options) {
|
|
229
|
+
|
|
230
|
+
const autoIndex = options.config && options.config.autoIndex != null ?
|
|
231
|
+
options.config.autoIndex :
|
|
232
|
+
options.autoIndex;
|
|
233
|
+
if (autoIndex != null) {
|
|
234
|
+
this.config.autoIndex = autoIndex !== false;
|
|
235
|
+
delete options.config;
|
|
236
|
+
delete options.autoIndex;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if ('autoCreate' in options) {
|
|
240
|
+
this.config.autoCreate = !!options.autoCreate;
|
|
241
|
+
delete options.autoCreate;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if ('sanitizeFilter' in options) {
|
|
245
|
+
this.config.sanitizeFilter = options.sanitizeFilter;
|
|
246
|
+
delete options.sanitizeFilter;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Backwards compat
|
|
250
|
+
if (options.user || options.pass) {
|
|
251
|
+
options.auth = options.auth || {};
|
|
252
|
+
options.auth.username = options.user;
|
|
253
|
+
options.auth.password = options.pass;
|
|
254
|
+
|
|
255
|
+
this.user = options.user;
|
|
256
|
+
this.pass = options.pass;
|
|
257
|
+
}
|
|
258
|
+
delete options.user;
|
|
259
|
+
delete options.pass;
|
|
260
|
+
|
|
261
|
+
if (options.bufferCommands != null) {
|
|
262
|
+
this.config.bufferCommands = options.bufferCommands;
|
|
263
|
+
delete options.bufferCommands;
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
options = {};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this._connectionOptions = options;
|
|
270
|
+
const dbName = options.dbName;
|
|
271
|
+
if (dbName != null) {
|
|
272
|
+
this.$dbName = dbName;
|
|
273
|
+
}
|
|
274
|
+
delete options.dbName;
|
|
275
|
+
|
|
276
|
+
if (!utils.hasUserDefinedProperty(options, 'driverInfo')) {
|
|
277
|
+
options.driverInfo = {
|
|
278
|
+
name: 'Mongoose',
|
|
279
|
+
version: pkg.version
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
this.readyState = STATES.connecting;
|
|
284
|
+
this._connectionString = uri;
|
|
285
|
+
|
|
286
|
+
let client;
|
|
287
|
+
try {
|
|
288
|
+
client = new mongodb.MongoClient(uri, options);
|
|
289
|
+
} catch (error) {
|
|
290
|
+
this.readyState = STATES.disconnected;
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
this.client = client;
|
|
294
|
+
|
|
295
|
+
client.setMaxListeners(0);
|
|
296
|
+
await client.connect();
|
|
297
|
+
|
|
298
|
+
_setClient(this, client, options, dbName);
|
|
299
|
+
|
|
300
|
+
for (const db of this.otherDbs) {
|
|
301
|
+
_setClient(db, client, {}, db.name);
|
|
302
|
+
}
|
|
303
|
+
return this;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
/*!
|
|
307
|
+
* ignore
|
|
308
|
+
*/
|
|
309
|
+
|
|
310
|
+
NativeConnection.prototype.setClient = function setClient(client) {
|
|
311
|
+
if (!(client instanceof mongodb.MongoClient)) {
|
|
312
|
+
throw new MongooseError('Must call `setClient()` with an instance of MongoClient');
|
|
313
|
+
}
|
|
314
|
+
if (this.readyState !== STATES.disconnected) {
|
|
315
|
+
throw new MongooseError('Cannot call `setClient()` on a connection that is already connected.');
|
|
316
|
+
}
|
|
317
|
+
if (client.topology == null) {
|
|
318
|
+
throw new MongooseError('Cannot call `setClient()` with a MongoClient that you have not called `connect()` on yet.');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
this._connectionString = client.s.url;
|
|
322
|
+
_setClient(this, client, {}, client.s.options.dbName);
|
|
323
|
+
|
|
324
|
+
for (const model of Object.values(this.models)) {
|
|
325
|
+
// Errors handled internally, so safe to ignore error
|
|
326
|
+
model.init().catch(function $modelInitNoop() {});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return this;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/*!
|
|
333
|
+
* ignore
|
|
334
|
+
*/
|
|
335
|
+
|
|
336
|
+
function _setClient(conn, client, options, dbName) {
|
|
337
|
+
const db = dbName != null ? client.db(dbName) : client.db();
|
|
338
|
+
conn.db = db;
|
|
339
|
+
conn.client = client;
|
|
340
|
+
conn.host = client &&
|
|
341
|
+
client.s &&
|
|
342
|
+
client.s.options &&
|
|
343
|
+
client.s.options.hosts &&
|
|
344
|
+
client.s.options.hosts[0] &&
|
|
345
|
+
client.s.options.hosts[0].host || void 0;
|
|
346
|
+
conn.port = client &&
|
|
347
|
+
client.s &&
|
|
348
|
+
client.s.options &&
|
|
349
|
+
client.s.options.hosts &&
|
|
350
|
+
client.s.options.hosts[0] &&
|
|
351
|
+
client.s.options.hosts[0].port || void 0;
|
|
352
|
+
conn.name = dbName != null ? dbName : client && client.s && client.s.options && client.s.options.dbName || void 0;
|
|
353
|
+
conn._closeCalled = client._closeCalled;
|
|
354
|
+
|
|
355
|
+
const _handleReconnect = () => {
|
|
356
|
+
// If we aren't disconnected, we assume this reconnect is due to a
|
|
357
|
+
// socket timeout. If there's no activity on a socket for
|
|
358
|
+
// `socketTimeoutMS`, the driver will attempt to reconnect and emit
|
|
359
|
+
// this event.
|
|
360
|
+
if (conn.readyState !== STATES.connected) {
|
|
361
|
+
conn.readyState = STATES.connected;
|
|
362
|
+
conn.emit('reconnect');
|
|
363
|
+
conn.emit('reconnected');
|
|
364
|
+
conn.onOpen();
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
const type = client &&
|
|
369
|
+
client.topology &&
|
|
370
|
+
client.topology.description &&
|
|
371
|
+
client.topology.description.type || '';
|
|
372
|
+
|
|
373
|
+
if (type === 'Single') {
|
|
374
|
+
client.on('serverDescriptionChanged', ev => {
|
|
375
|
+
const newDescription = ev.newDescription;
|
|
376
|
+
if (newDescription.type === 'Unknown') {
|
|
377
|
+
conn.readyState = STATES.disconnected;
|
|
378
|
+
} else {
|
|
379
|
+
_handleReconnect();
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
} else if (type.startsWith('ReplicaSet')) {
|
|
383
|
+
client.on('topologyDescriptionChanged', ev => {
|
|
384
|
+
// Emit disconnected if we've lost connectivity to the primary
|
|
385
|
+
const description = ev.newDescription;
|
|
386
|
+
if (conn.readyState === STATES.connected && description.type !== 'ReplicaSetWithPrimary') {
|
|
387
|
+
// Implicitly emits 'disconnected'
|
|
388
|
+
conn.readyState = STATES.disconnected;
|
|
389
|
+
} else if (conn.readyState === STATES.disconnected && description.type === 'ReplicaSetWithPrimary') {
|
|
390
|
+
_handleReconnect();
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
conn.onOpen();
|
|
396
|
+
|
|
397
|
+
for (const i in conn.collections) {
|
|
398
|
+
if (utils.object.hasOwnProperty(conn.collections, i)) {
|
|
399
|
+
conn.collections[i].onOpen();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
157
404
|
|
|
158
405
|
/*!
|
|
159
406
|
* Module exports.
|
package/lib/error/cast.js
CHANGED
|
@@ -20,10 +20,9 @@ class CastError extends MongooseError {
|
|
|
20
20
|
constructor(type, value, path, reason, schemaType) {
|
|
21
21
|
// If no args, assume we'll `init()` later.
|
|
22
22
|
if (arguments.length > 0) {
|
|
23
|
-
const stringValue = getStringValue(value);
|
|
24
23
|
const valueType = getValueType(value);
|
|
25
24
|
const messageFormat = getMessageFormat(schemaType);
|
|
26
|
-
const msg = formatMessage(null, type,
|
|
25
|
+
const msg = formatMessage(null, type, value, path, messageFormat, valueType, reason);
|
|
27
26
|
super(msg);
|
|
28
27
|
this.init(type, value, path, reason, schemaType);
|
|
29
28
|
} else {
|
|
@@ -77,7 +76,7 @@ class CastError extends MongooseError {
|
|
|
77
76
|
*/
|
|
78
77
|
setModel(model) {
|
|
79
78
|
this.model = model;
|
|
80
|
-
this.message = formatMessage(model, this.kind, this.
|
|
79
|
+
this.message = formatMessage(model, this.kind, this.value, this.path,
|
|
81
80
|
this.messageFormat, this.valueType);
|
|
82
81
|
}
|
|
83
82
|
}
|
|
@@ -111,10 +110,8 @@ function getValueType(value) {
|
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
function getMessageFormat(schemaType) {
|
|
114
|
-
const messageFormat = schemaType &&
|
|
115
|
-
|
|
116
|
-
schemaType.options.cast || null;
|
|
117
|
-
if (typeof messageFormat === 'string') {
|
|
113
|
+
const messageFormat = schemaType && schemaType._castErrorMessage || null;
|
|
114
|
+
if (typeof messageFormat === 'string' || typeof messageFormat === 'function') {
|
|
118
115
|
return messageFormat;
|
|
119
116
|
}
|
|
120
117
|
}
|
|
@@ -123,8 +120,9 @@ function getMessageFormat(schemaType) {
|
|
|
123
120
|
* ignore
|
|
124
121
|
*/
|
|
125
122
|
|
|
126
|
-
function formatMessage(model, kind,
|
|
127
|
-
if (messageFormat
|
|
123
|
+
function formatMessage(model, kind, value, path, messageFormat, valueType, reason) {
|
|
124
|
+
if (typeof messageFormat === 'string') {
|
|
125
|
+
const stringValue = getStringValue(value);
|
|
128
126
|
let ret = messageFormat.
|
|
129
127
|
replace('{KIND}', kind).
|
|
130
128
|
replace('{VALUE}', stringValue).
|
|
@@ -134,7 +132,10 @@ function formatMessage(model, kind, stringValue, path, messageFormat, valueType,
|
|
|
134
132
|
}
|
|
135
133
|
|
|
136
134
|
return ret;
|
|
135
|
+
} else if (typeof messageFormat === 'function') {
|
|
136
|
+
return messageFormat(value, path, model, kind);
|
|
137
137
|
} else {
|
|
138
|
+
const stringValue = getStringValue(value);
|
|
138
139
|
const valueTypeMsg = valueType ? ' (type ' + valueType + ')' : '';
|
|
139
140
|
let ret = 'Cast to ' + kind + ' failed for value ' +
|
|
140
141
|
stringValue + valueTypeMsg + ' at path "' + path + '"';
|
package/lib/error/messages.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* const mongoose = require('mongoose');
|
|
7
7
|
* mongoose.Error.messages.String.enum = "Your custom message for {PATH}.";
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* Error messages support basic templating. Mongoose will replace the following strings with the corresponding value.
|
|
10
10
|
*
|
|
11
11
|
* - `{PATH}` is replaced with the invalid document path
|
|
12
12
|
* - `{VALUE}` is replaced with the invalid value
|
|
@@ -12,8 +12,8 @@ module.exports = function addIdGetter(schema) {
|
|
|
12
12
|
if (!autoIdGetter) {
|
|
13
13
|
return schema;
|
|
14
14
|
}
|
|
15
|
-
|
|
16
15
|
schema.virtual('id').get(idGetter);
|
|
16
|
+
schema.virtual('id').set(idSetter);
|
|
17
17
|
|
|
18
18
|
return schema;
|
|
19
19
|
};
|
|
@@ -30,3 +30,14 @@ function idGetter() {
|
|
|
30
30
|
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param {String} v the id to set
|
|
37
|
+
* @api private
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
function idSetter(v) {
|
|
41
|
+
this._id = v;
|
|
42
|
+
return v;
|
|
43
|
+
}
|
package/lib/model.js
CHANGED
|
@@ -320,7 +320,6 @@ Model.prototype.$__handleSave = function(options, callback) {
|
|
|
320
320
|
_setIsNew(this, false);
|
|
321
321
|
// Make it possible to retry the insert
|
|
322
322
|
this.$__.inserting = true;
|
|
323
|
-
|
|
324
323
|
return;
|
|
325
324
|
}
|
|
326
325
|
|
|
@@ -479,7 +478,6 @@ function generateVersionError(doc, modifiedPaths) {
|
|
|
479
478
|
* newProduct === product; // true
|
|
480
479
|
*
|
|
481
480
|
* @param {Object} [options] options optional options
|
|
482
|
-
* @param {Boolean} [options.ordered] saves the docs in series rather than parallel.
|
|
483
481
|
* @param {Session} [options.session=null] the [session](https://www.mongodb.com/docs/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](https://mongoosejs.com/docs/api/document.html#Document.prototype.session()).
|
|
484
482
|
* @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](https://mongoosejs.com/docs/guide.html#safe). Use the `w` option instead.
|
|
485
483
|
* @param {Boolean} [options.validateBeforeSave] set to false to save without validating.
|
|
@@ -1372,6 +1370,14 @@ Model.createCollection = async function createCollection(options) {
|
|
|
1372
1370
|
throw new MongooseError('Model.createCollection() no longer accepts a callback');
|
|
1373
1371
|
}
|
|
1374
1372
|
|
|
1373
|
+
const collectionOptions = this &&
|
|
1374
|
+
this.schema &&
|
|
1375
|
+
this.schema.options &&
|
|
1376
|
+
this.schema.options.collectionOptions;
|
|
1377
|
+
if (collectionOptions != null) {
|
|
1378
|
+
options = Object.assign({}, collectionOptions, options);
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1375
1381
|
const schemaCollation = this &&
|
|
1376
1382
|
this.schema &&
|
|
1377
1383
|
this.schema.options &&
|
|
@@ -2802,6 +2808,8 @@ Model.findByIdAndRemove = function(id, options) {
|
|
|
2802
2808
|
*
|
|
2803
2809
|
* @param {Array|Object} docs Documents to insert, as a spread or array
|
|
2804
2810
|
* @param {Object} [options] Options passed down to `save()`. To specify `options`, `docs` **must** be an array, not a spread. See [Model.save](https://mongoosejs.com/docs/api/model.html#Model.prototype.save()) for available options.
|
|
2811
|
+
* @param {Boolean} [options.ordered] saves the docs in series rather than parallel.
|
|
2812
|
+
* @param {Boolean} [options.aggregateErrors] Aggregate Errors instead of throwing the first one that occurs. Default: false
|
|
2805
2813
|
* @return {Promise}
|
|
2806
2814
|
* @api public
|
|
2807
2815
|
*/
|
|
@@ -2858,27 +2866,41 @@ Model.create = async function create(doc, options) {
|
|
|
2858
2866
|
return Array.isArray(doc) ? [] : null;
|
|
2859
2867
|
}
|
|
2860
2868
|
let res = [];
|
|
2869
|
+
const immediateError = typeof options.aggregateErrors === 'boolean' ? !options.aggregateErrors : true;
|
|
2870
|
+
|
|
2871
|
+
delete options.aggregateErrors; // dont pass on the option to "$save"
|
|
2872
|
+
|
|
2861
2873
|
if (options.ordered) {
|
|
2862
2874
|
for (let i = 0; i < args.length; i++) {
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2875
|
+
try {
|
|
2876
|
+
const doc = args[i];
|
|
2877
|
+
const Model = this.discriminators && doc[discriminatorKey] != null ?
|
|
2878
|
+
this.discriminators[doc[discriminatorKey]] || getDiscriminatorByValue(this.discriminators, doc[discriminatorKey]) :
|
|
2879
|
+
this;
|
|
2880
|
+
if (Model == null) {
|
|
2881
|
+
throw new MongooseError(`Discriminator "${doc[discriminatorKey]}" not ` +
|
|
2869
2882
|
`found for model "${this.modelName}"`);
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2883
|
+
}
|
|
2884
|
+
let toSave = doc;
|
|
2885
|
+
if (!(toSave instanceof Model)) {
|
|
2886
|
+
toSave = new Model(toSave);
|
|
2887
|
+
}
|
|
2875
2888
|
|
|
2876
|
-
|
|
2877
|
-
|
|
2889
|
+
await toSave.$save(options);
|
|
2890
|
+
res.push(toSave);
|
|
2891
|
+
} catch (err) {
|
|
2892
|
+
if (!immediateError) {
|
|
2893
|
+
res.push(err);
|
|
2894
|
+
} else {
|
|
2895
|
+
throw err;
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2878
2898
|
}
|
|
2879
2899
|
return res;
|
|
2880
2900
|
} else {
|
|
2881
|
-
|
|
2901
|
+
// ".bind(Promise)" is required, otherwise results in "TypeError: Promise.allSettled called on non-object"
|
|
2902
|
+
const promiseType = !immediateError ? Promise.allSettled.bind(Promise) : Promise.all.bind(Promise);
|
|
2903
|
+
let p = promiseType(args.map(async doc => {
|
|
2882
2904
|
const Model = this.discriminators && doc[discriminatorKey] != null ?
|
|
2883
2905
|
this.discriminators[doc[discriminatorKey]] || getDiscriminatorByValue(this.discriminators, doc[discriminatorKey]) :
|
|
2884
2906
|
this;
|
|
@@ -2896,6 +2918,13 @@ Model.create = async function create(doc, options) {
|
|
|
2896
2918
|
|
|
2897
2919
|
return toSave;
|
|
2898
2920
|
}));
|
|
2921
|
+
|
|
2922
|
+
// chain the mapper, only if "allSettled" is used
|
|
2923
|
+
if (!immediateError) {
|
|
2924
|
+
p = p.then(presult => presult.map(v => v.status === 'fulfilled' ? v.value : v.reason));
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
res = await p;
|
|
2899
2928
|
}
|
|
2900
2929
|
|
|
2901
2930
|
|
package/lib/query.js
CHANGED
|
@@ -24,6 +24,7 @@ const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminato
|
|
|
24
24
|
const hasDollarKeys = require('./helpers/query/hasDollarKeys');
|
|
25
25
|
const helpers = require('./queryhelpers');
|
|
26
26
|
const immediate = require('./helpers/immediate');
|
|
27
|
+
const internalToObjectOptions = require('./options').internalToObjectOptions;
|
|
27
28
|
const isExclusive = require('./helpers/projection/isExclusive');
|
|
28
29
|
const isInclusive = require('./helpers/projection/isInclusive');
|
|
29
30
|
const isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
|
|
@@ -1635,6 +1636,10 @@ Query.prototype.setOptions = function(options, overwrite) {
|
|
|
1635
1636
|
delete options.translateAliases;
|
|
1636
1637
|
}
|
|
1637
1638
|
|
|
1639
|
+
if ('rawResult' in options) {
|
|
1640
|
+
printRawResultDeprecationWarning();
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1638
1643
|
if (options.lean == null && this.schema && 'lean' in this.schema.options) {
|
|
1639
1644
|
this._mongooseOptions.lean = this.schema.options.lean;
|
|
1640
1645
|
}
|
|
@@ -1669,6 +1674,15 @@ Query.prototype.setOptions = function(options, overwrite) {
|
|
|
1669
1674
|
return this;
|
|
1670
1675
|
};
|
|
1671
1676
|
|
|
1677
|
+
/*!
|
|
1678
|
+
* ignore
|
|
1679
|
+
*/
|
|
1680
|
+
|
|
1681
|
+
const printRawResultDeprecationWarning = util.deprecate(
|
|
1682
|
+
function printRawResultDeprecationWarning() {},
|
|
1683
|
+
'The `rawResult` option for Mongoose queries is deprecated. Use `includeResultMetadata: false` as a replacement for `rawResult: true`.'
|
|
1684
|
+
);
|
|
1685
|
+
|
|
1672
1686
|
/**
|
|
1673
1687
|
* Sets the [`explain` option](https://www.mongodb.com/docs/manual/reference/method/cursor.explain/),
|
|
1674
1688
|
* which makes this query return detailed execution stats instead of the actual
|
|
@@ -2319,8 +2333,6 @@ Query.prototype.find = function(conditions) {
|
|
|
2319
2333
|
|
|
2320
2334
|
this.op = 'find';
|
|
2321
2335
|
|
|
2322
|
-
conditions = utils.toObject(conditions);
|
|
2323
|
-
|
|
2324
2336
|
if (mquery.canMerge(conditions)) {
|
|
2325
2337
|
this.merge(conditions);
|
|
2326
2338
|
|
|
@@ -2392,6 +2404,8 @@ Query.prototype.merge = function(source) {
|
|
|
2392
2404
|
utils.merge(this._conditions, { _id: source }, opts);
|
|
2393
2405
|
|
|
2394
2406
|
return this;
|
|
2407
|
+
} else if (source && source.$__) {
|
|
2408
|
+
source = source.toObject(internalToObjectOptions);
|
|
2395
2409
|
}
|
|
2396
2410
|
|
|
2397
2411
|
opts.omit = {};
|
|
@@ -2434,7 +2448,7 @@ Query.prototype.collation = function(value) {
|
|
|
2434
2448
|
*/
|
|
2435
2449
|
|
|
2436
2450
|
Query.prototype._completeOne = function(doc, res, callback) {
|
|
2437
|
-
if (!doc && !this.options.rawResult) {
|
|
2451
|
+
if (!doc && !this.options.rawResult && !this.options.includeResultMetadata) {
|
|
2438
2452
|
return callback(null, null);
|
|
2439
2453
|
}
|
|
2440
2454
|
|
|
@@ -2560,9 +2574,6 @@ Query.prototype.findOne = function(conditions, projection, options) {
|
|
|
2560
2574
|
this.op = 'findOne';
|
|
2561
2575
|
this._validateOp();
|
|
2562
2576
|
|
|
2563
|
-
// make sure we don't send in the whole Document to merge()
|
|
2564
|
-
conditions = utils.toObject(conditions);
|
|
2565
|
-
|
|
2566
2577
|
if (options) {
|
|
2567
2578
|
this.setOptions(options);
|
|
2568
2579
|
}
|
|
@@ -2726,8 +2737,6 @@ Query.prototype.count = function(filter) {
|
|
|
2726
2737
|
this.op = 'count';
|
|
2727
2738
|
this._validateOp();
|
|
2728
2739
|
|
|
2729
|
-
filter = utils.toObject(filter);
|
|
2730
|
-
|
|
2731
2740
|
if (mquery.canMerge(filter)) {
|
|
2732
2741
|
this.merge(filter);
|
|
2733
2742
|
}
|
|
@@ -2822,8 +2831,6 @@ Query.prototype.countDocuments = function(conditions, options) {
|
|
|
2822
2831
|
this.op = 'countDocuments';
|
|
2823
2832
|
this._validateOp();
|
|
2824
2833
|
|
|
2825
|
-
conditions = utils.toObject(conditions);
|
|
2826
|
-
|
|
2827
2834
|
if (mquery.canMerge(conditions)) {
|
|
2828
2835
|
this.merge(conditions);
|
|
2829
2836
|
}
|
|
@@ -2886,7 +2893,6 @@ Query.prototype.distinct = function(field, conditions) {
|
|
|
2886
2893
|
|
|
2887
2894
|
this.op = 'distinct';
|
|
2888
2895
|
this._validateOp();
|
|
2889
|
-
conditions = utils.toObject(conditions);
|
|
2890
2896
|
|
|
2891
2897
|
if (mquery.canMerge(conditions)) {
|
|
2892
2898
|
this.merge(conditions);
|
|
@@ -2981,8 +2987,6 @@ Query.prototype.deleteOne = function deleteOne(filter, options) {
|
|
|
2981
2987
|
this.op = 'deleteOne';
|
|
2982
2988
|
this.setOptions(options);
|
|
2983
2989
|
|
|
2984
|
-
filter = utils.toObject(filter);
|
|
2985
|
-
|
|
2986
2990
|
if (mquery.canMerge(filter)) {
|
|
2987
2991
|
this.merge(filter);
|
|
2988
2992
|
|
|
@@ -3058,8 +3062,6 @@ Query.prototype.deleteMany = function(filter, options) {
|
|
|
3058
3062
|
this.setOptions(options);
|
|
3059
3063
|
this.op = 'deleteMany';
|
|
3060
3064
|
|
|
3061
|
-
filter = utils.toObject(filter);
|
|
3062
|
-
|
|
3063
3065
|
if (mquery.canMerge(filter)) {
|
|
3064
3066
|
this.merge(filter);
|
|
3065
3067
|
|
|
@@ -3110,7 +3112,7 @@ Query.prototype._deleteMany = async function _deleteMany() {
|
|
|
3110
3112
|
*/
|
|
3111
3113
|
|
|
3112
3114
|
function completeOne(model, doc, res, options, fields, userProvidedFields, pop, callback) {
|
|
3113
|
-
if (options.rawResult && doc == null) {
|
|
3115
|
+
if ((options.rawResult || options.includeResultMetadata) && doc == null) {
|
|
3114
3116
|
_init(null);
|
|
3115
3117
|
return null;
|
|
3116
3118
|
}
|
|
@@ -3123,7 +3125,7 @@ function completeOne(model, doc, res, options, fields, userProvidedFields, pop,
|
|
|
3123
3125
|
}
|
|
3124
3126
|
|
|
3125
3127
|
|
|
3126
|
-
if (options.rawResult) {
|
|
3128
|
+
if (options.rawResult || options.includeResultMetadata) {
|
|
3127
3129
|
if (doc && casted) {
|
|
3128
3130
|
if (options.session != null) {
|
|
3129
3131
|
casted.$session(options.session);
|
|
@@ -3298,6 +3300,10 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
|
|
|
3298
3300
|
applyGlobalMaxTimeMS(this.options, this.model);
|
|
3299
3301
|
applyGlobalDiskUse(this.options, this.model);
|
|
3300
3302
|
|
|
3303
|
+
if (this.options.rawResult && this.options.includeResultMetadata === false) {
|
|
3304
|
+
throw new MongooseError('Cannot set `rawResult` option when `includeResultMetadata` is false');
|
|
3305
|
+
}
|
|
3306
|
+
|
|
3301
3307
|
if ('strict' in this.options) {
|
|
3302
3308
|
this._mongooseOptions.strict = this.options.strict;
|
|
3303
3309
|
}
|
|
@@ -3348,7 +3354,7 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
|
|
|
3348
3354
|
for (const fn of this._transforms) {
|
|
3349
3355
|
res = fn(res);
|
|
3350
3356
|
}
|
|
3351
|
-
const doc = res.value;
|
|
3357
|
+
const doc = options.includeResultMetadata === false ? res : res.value;
|
|
3352
3358
|
|
|
3353
3359
|
return new Promise((resolve, reject) => {
|
|
3354
3360
|
this._completeOne(doc, res, _wrapThunkCallback(this, (err, res) => {
|
|
@@ -3489,6 +3495,11 @@ Query.prototype._findOneAndDelete = async function _findOneAndDelete() {
|
|
|
3489
3495
|
throw this.error();
|
|
3490
3496
|
}
|
|
3491
3497
|
|
|
3498
|
+
const includeResultMetadata = this.options.includeResultMetadata;
|
|
3499
|
+
if (this.options.rawResult && includeResultMetadata === false) {
|
|
3500
|
+
throw new MongooseError('Cannot set `rawResult` option when `includeResultMetadata` is false');
|
|
3501
|
+
}
|
|
3502
|
+
|
|
3492
3503
|
const filter = this._conditions;
|
|
3493
3504
|
const options = this._optionsForExec(this.model);
|
|
3494
3505
|
this._applyTranslateAliases(options);
|
|
@@ -3497,7 +3508,7 @@ Query.prototype._findOneAndDelete = async function _findOneAndDelete() {
|
|
|
3497
3508
|
for (const fn of this._transforms) {
|
|
3498
3509
|
res = fn(res);
|
|
3499
3510
|
}
|
|
3500
|
-
const doc = res.value;
|
|
3511
|
+
const doc = includeResultMetadata === false ? res : res.value;
|
|
3501
3512
|
|
|
3502
3513
|
return new Promise((resolve, reject) => {
|
|
3503
3514
|
this._completeOne(doc, res, _wrapThunkCallback(this, (err, res) => {
|
|
@@ -3624,6 +3635,11 @@ Query.prototype._findOneAndReplace = async function _findOneAndReplace() {
|
|
|
3624
3635
|
this._applyTranslateAliases(options);
|
|
3625
3636
|
convertNewToReturnDocument(options);
|
|
3626
3637
|
|
|
3638
|
+
const includeResultMetadata = this.options.includeResultMetadata;
|
|
3639
|
+
if (this.options.rawResult && includeResultMetadata === false) {
|
|
3640
|
+
throw new MongooseError('Cannot set `rawResult` option when `includeResultMetadata` is false');
|
|
3641
|
+
}
|
|
3642
|
+
|
|
3627
3643
|
const modelOpts = { skipId: true };
|
|
3628
3644
|
if ('strict' in this._mongooseOptions) {
|
|
3629
3645
|
modelOpts.strict = this._mongooseOptions.strict;
|
|
@@ -3654,7 +3670,7 @@ Query.prototype._findOneAndReplace = async function _findOneAndReplace() {
|
|
|
3654
3670
|
res = fn(res);
|
|
3655
3671
|
}
|
|
3656
3672
|
|
|
3657
|
-
const doc = res.value;
|
|
3673
|
+
const doc = includeResultMetadata === false ? res : res.value;
|
|
3658
3674
|
return new Promise((resolve, reject) => {
|
|
3659
3675
|
this._completeOne(doc, res, _wrapThunkCallback(this, (err, res) => {
|
|
3660
3676
|
if (err) {
|
|
@@ -4168,7 +4184,6 @@ function _update(query, op, filter, doc, options, callback) {
|
|
|
4168
4184
|
// make sure we don't send in the whole Document to merge()
|
|
4169
4185
|
query.op = op;
|
|
4170
4186
|
query._validateOp();
|
|
4171
|
-
filter = utils.toObject(filter);
|
|
4172
4187
|
doc = doc || {};
|
|
4173
4188
|
|
|
4174
4189
|
// strict is an option used in the update checking, make sure it gets set
|