mongoose 5.4.23 → 5.5.3
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/History.md +50 -0
- package/lib/aggregate.js +16 -4
- package/lib/connection.js +58 -1
- package/lib/document.js +195 -36
- package/lib/drivers/node-mongodb-native/collection.js +16 -4
- package/lib/drivers/node-mongodb-native/index.js +1 -1
- package/lib/helpers/document/cleanModifiedSubpaths.js +3 -0
- package/lib/helpers/document/compile.js +16 -1
- package/lib/helpers/document/getEmbeddedDiscriminatorPath.js +5 -5
- package/lib/helpers/model/applyHooks.js +4 -1
- package/lib/helpers/model/applyStaticHooks.js +61 -0
- package/lib/helpers/populate/assignVals.js +11 -1
- package/lib/helpers/query/applyQueryMiddleware.js +6 -2
- package/lib/helpers/query/castUpdate.js +0 -2
- package/lib/helpers/schema/applyPlugins.js +43 -0
- package/lib/helpers/symbols.js +4 -8
- package/lib/index.js +22 -36
- package/lib/internal.js +1 -0
- package/lib/model.js +155 -33
- package/lib/plugins/validateBeforeSave.js +7 -1
- package/lib/query.js +135 -29
- package/lib/schema/array.js +50 -0
- package/lib/schema/documentarray.js +39 -25
- package/lib/schema.js +6 -5
- package/lib/schematype.js +51 -6
- package/lib/types/array.js +20 -21
- package/lib/types/buffer.js +8 -34
- package/lib/types/documentarray.js +4 -3
- package/lib/types/embedded.js +1 -1
- package/lib/types/subdocument.js +27 -1
- package/package.json +6 -5
|
@@ -14,6 +14,7 @@ module.exports = applyHooks;
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
applyHooks.middlewareFunctions = [
|
|
17
|
+
'deleteOne',
|
|
17
18
|
'save',
|
|
18
19
|
'validate',
|
|
19
20
|
'remove',
|
|
@@ -71,7 +72,7 @@ function applyHooks(model, schema, options) {
|
|
|
71
72
|
|
|
72
73
|
const middleware = schema.s.hooks.
|
|
73
74
|
filter(hook => {
|
|
74
|
-
if (hook.name === 'updateOne') {
|
|
75
|
+
if (hook.name === 'updateOne' || hook.name === 'deleteOne') {
|
|
75
76
|
return !!hook['document'];
|
|
76
77
|
}
|
|
77
78
|
if (hook.name === 'remove') {
|
|
@@ -96,6 +97,8 @@ function applyHooks(model, schema, options) {
|
|
|
96
97
|
createWrapper('validate', objToDecorate.$__validate, null, kareemOptions);
|
|
97
98
|
objToDecorate.$__remove = middleware.
|
|
98
99
|
createWrapper('remove', objToDecorate.$__remove, null, kareemOptions);
|
|
100
|
+
objToDecorate.$__deleteOne = middleware.
|
|
101
|
+
createWrapper('deleteOne', objToDecorate.$__deleteOne, null, kareemOptions);
|
|
99
102
|
objToDecorate.$__init = middleware.
|
|
100
103
|
createWrapperSync('init', objToDecorate.$__init, null, kareemOptions);
|
|
101
104
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const utils = require('../../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = function applyStaticHooks(model, hooks, statics) {
|
|
6
|
+
const kareemOptions = {
|
|
7
|
+
useErrorHandlers: true,
|
|
8
|
+
numCallbackParams: 1
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
hooks = hooks.filter(hook => hook.model !== false);
|
|
12
|
+
|
|
13
|
+
model.$__insertMany = hooks.createWrapper('insertMany',
|
|
14
|
+
model.$__insertMany, model, kareemOptions);
|
|
15
|
+
|
|
16
|
+
for (const key of Object.keys(statics)) {
|
|
17
|
+
if (hooks.hasHooks(key)) {
|
|
18
|
+
const original = model[key];
|
|
19
|
+
|
|
20
|
+
model[key] = function() {
|
|
21
|
+
const numArgs = arguments.length;
|
|
22
|
+
const lastArg = numArgs > 0 ? arguments[numArgs - 1] : null;
|
|
23
|
+
const cb = typeof lastArg === 'function' ? lastArg : null;
|
|
24
|
+
const args = Array.prototype.slice.
|
|
25
|
+
call(arguments, 0, cb == null ? numArgs : numArgs - 1);
|
|
26
|
+
// Special case: can't use `Kareem#wrap()` because it doesn't currently
|
|
27
|
+
// support wrapped functions that return a promise.
|
|
28
|
+
return utils.promiseOrCallback(cb, callback => {
|
|
29
|
+
hooks.execPre(key, model, args, function(err) {
|
|
30
|
+
if (err != null) {
|
|
31
|
+
return callback(err);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let postCalled = 0;
|
|
35
|
+
const ret = original.apply(model, args.concat(post));
|
|
36
|
+
if (ret != null && typeof ret.then === 'function') {
|
|
37
|
+
ret.then(res => post(null, res), err => post(err));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function post(error, res) {
|
|
41
|
+
if (postCalled++ > 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (error != null) {
|
|
46
|
+
return callback(error);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
hooks.execPost(key, model, [res], function(error) {
|
|
50
|
+
if (error != null) {
|
|
51
|
+
return callback(error);
|
|
52
|
+
}
|
|
53
|
+
callback(null, res);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}, model.events);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
@@ -6,6 +6,7 @@ const get = require('../get');
|
|
|
6
6
|
const getVirtual = require('./getVirtual');
|
|
7
7
|
const leanPopulateMap = require('./leanPopulateMap');
|
|
8
8
|
const mpath = require('mpath');
|
|
9
|
+
const sift = require('sift').default;
|
|
9
10
|
const utils = require('../../utils');
|
|
10
11
|
|
|
11
12
|
module.exports = function assignVals(o) {
|
|
@@ -48,7 +49,16 @@ module.exports = function assignVals(o) {
|
|
|
48
49
|
continue;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
let valueToSet
|
|
52
|
+
let valueToSet;
|
|
53
|
+
if (count) {
|
|
54
|
+
valueToSet = numDocs(rawIds[i]);
|
|
55
|
+
} else if (Array.isArray(o.match)) {
|
|
56
|
+
valueToSet = Array.isArray(rawIds[i]) ?
|
|
57
|
+
sift(o.match[i], rawIds[i]) :
|
|
58
|
+
sift(o.match[i], [rawIds[i]])[0];
|
|
59
|
+
} else {
|
|
60
|
+
valueToSet = rawIds[i];
|
|
61
|
+
}
|
|
52
62
|
|
|
53
63
|
// If we're populating a map, the existing value will be an object, so
|
|
54
64
|
// we need to transform again
|
|
@@ -15,6 +15,7 @@ applyQueryMiddleware.middlewareFunctions = [
|
|
|
15
15
|
'countDocuments',
|
|
16
16
|
'deleteMany',
|
|
17
17
|
'deleteOne',
|
|
18
|
+
'distinct',
|
|
18
19
|
'estimatedDocumentCount',
|
|
19
20
|
'find',
|
|
20
21
|
'findOne',
|
|
@@ -44,7 +45,7 @@ function applyQueryMiddleware(Query, model) {
|
|
|
44
45
|
};
|
|
45
46
|
|
|
46
47
|
const middleware = model.hooks.filter(hook => {
|
|
47
|
-
if (hook.name === 'updateOne') {
|
|
48
|
+
if (hook.name === 'updateOne' || hook.name === 'deleteOne') {
|
|
48
49
|
return hook.query == null || !!hook.query;
|
|
49
50
|
}
|
|
50
51
|
if (hook.name === 'remove') {
|
|
@@ -56,9 +57,12 @@ function applyQueryMiddleware(Query, model) {
|
|
|
56
57
|
// `update()` thunk has a different name because `_update` was already taken
|
|
57
58
|
Query.prototype._execUpdate = middleware.createWrapper('update',
|
|
58
59
|
Query.prototype._execUpdate, null, kareemOptions);
|
|
60
|
+
// `distinct()` thunk has a different name because `_distinct` was already taken
|
|
61
|
+
Query.prototype.__distinct = middleware.createWrapper('distinct',
|
|
62
|
+
Query.prototype.__distinct, null, kareemOptions);
|
|
59
63
|
|
|
60
64
|
applyQueryMiddleware.middlewareFunctions.
|
|
61
|
-
filter(v => v !== 'update').
|
|
65
|
+
filter(v => v !== 'update' && v !== 'distinct').
|
|
62
66
|
forEach(fn => {
|
|
63
67
|
Query.prototype[`_${fn}`] = middleware.createWrapper(fn,
|
|
64
68
|
Query.prototype[`_${fn}`], null, kareemOptions);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = function applyPlugins(schema, plugins, options, cacheKey) {
|
|
4
|
+
if (schema[cacheKey]) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
schema[cacheKey] = true;
|
|
8
|
+
|
|
9
|
+
if (!options || !options.skipTopLevel) {
|
|
10
|
+
for (let i = 0; i < plugins.length; ++i) {
|
|
11
|
+
schema.plugin(plugins[i][0], plugins[i][1]);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
options = Object.assign({}, options);
|
|
16
|
+
delete options.skipTopLevel;
|
|
17
|
+
|
|
18
|
+
for (const path of Object.keys(schema.paths)) {
|
|
19
|
+
const type = schema.paths[path];
|
|
20
|
+
if (type.schema != null) {
|
|
21
|
+
applyPlugins(type.schema, plugins, options, cacheKey);
|
|
22
|
+
|
|
23
|
+
// Recompile schema because plugins may have changed it, see gh-7572
|
|
24
|
+
type.caster.prototype.$__setSchema(type.schema);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const discriminators = schema.discriminators;
|
|
29
|
+
if (discriminators == null) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const applyPluginsToDiscriminators = options.applyPluginsToDiscriminators;
|
|
34
|
+
|
|
35
|
+
const keys = Object.keys(discriminators);
|
|
36
|
+
for (let i = 0; i < keys.length; ++i) {
|
|
37
|
+
const discriminatorKey = keys[i];
|
|
38
|
+
const discriminatorSchema = discriminators[discriminatorKey];
|
|
39
|
+
|
|
40
|
+
applyPlugins(discriminatorSchema, plugins,
|
|
41
|
+
{ skipTopLevel: !applyPluginsToDiscriminators }, cacheKey);
|
|
42
|
+
}
|
|
43
|
+
};
|
package/lib/helpers/symbols.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
exports.
|
|
4
|
-
|
|
3
|
+
exports.arrayParentSymbol = Symbol('mongoose#Array#_parent');
|
|
5
4
|
exports.documentArrayParent = Symbol.for('mongoose:documentArrayParent');
|
|
6
|
-
|
|
7
|
-
exports.modelSymbol = Symbol.for('mongoose#Model');
|
|
8
|
-
|
|
9
5
|
exports.getSymbol = Symbol.for('mongoose#Document#get');
|
|
10
|
-
|
|
6
|
+
exports.modelSymbol = Symbol.for('mongoose#Model');
|
|
11
7
|
exports.objectIdSymbol = Symbol.for('mongoose#ObjectId');
|
|
12
|
-
|
|
13
|
-
exports.
|
|
8
|
+
exports.schemaTypeSymbol = Symbol.for('mongoose#schemaType');
|
|
9
|
+
exports.validatorErrorSymbol = Symbol.for('mongoose:validatorError');
|
package/lib/index.js
CHANGED
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
if (global.MONGOOSE_DRIVER_PATH) {
|
|
8
|
-
|
|
8
|
+
const deprecationWarning = 'The `MONGOOSE_DRIVER_PATH` global property is ' +
|
|
9
|
+
'deprecated. Use `mongoose.driver.set()` instead.';
|
|
10
|
+
const setDriver = require('util').deprecate(function() {
|
|
11
|
+
require('./driver').set(require(global.MONGOOSE_DRIVER_PATH));
|
|
12
|
+
}, deprecationWarning);
|
|
13
|
+
setDriver();
|
|
9
14
|
} else {
|
|
10
15
|
require('./driver').set(require('./drivers/node-mongodb-native'));
|
|
11
16
|
}
|
|
@@ -19,6 +24,7 @@ const Types = require('./types');
|
|
|
19
24
|
const Query = require('./query');
|
|
20
25
|
const Model = require('./model');
|
|
21
26
|
const Document = require('./document');
|
|
27
|
+
const applyPlugins = require('./helpers/schema/applyPlugins');
|
|
22
28
|
const get = require('./helpers/get');
|
|
23
29
|
const legacyPluralize = require('mongoose-legacy-pluralize');
|
|
24
30
|
const utils = require('./utils');
|
|
@@ -103,6 +109,18 @@ function Mongoose(options) {
|
|
|
103
109
|
*/
|
|
104
110
|
Mongoose.prototype.STATES = STATES;
|
|
105
111
|
|
|
112
|
+
/**
|
|
113
|
+
* The underlying driver this Mongoose instance uses to communicate with
|
|
114
|
+
* the database. A driver is a Mongoose-specific interface that defines functions
|
|
115
|
+
* like `find()`.
|
|
116
|
+
*
|
|
117
|
+
* @memberOf Mongoose
|
|
118
|
+
* @property driver
|
|
119
|
+
* @api public
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
Mongoose.prototype.driver = require('./driver');
|
|
123
|
+
|
|
106
124
|
/**
|
|
107
125
|
* Sets mongoose options
|
|
108
126
|
*
|
|
@@ -553,42 +571,10 @@ Mongoose.prototype.modelNames = function() {
|
|
|
553
571
|
*/
|
|
554
572
|
|
|
555
573
|
Mongoose.prototype._applyPlugins = function(schema, options) {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
schema.$globalPluginsApplied = true;
|
|
560
|
-
|
|
561
|
-
if (!options || !options.skipTopLevel) {
|
|
562
|
-
for (let i = 0; i < this.plugins.length; ++i) {
|
|
563
|
-
schema.plugin(this.plugins[i][0], this.plugins[i][1]);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
for (const path of Object.keys(schema.paths)) {
|
|
568
|
-
const type = schema.paths[path];
|
|
569
|
-
if (type.schema != null) {
|
|
570
|
-
this._applyPlugins(type.schema);
|
|
571
|
-
|
|
572
|
-
// Recompile schema because plugins may have changed it, see gh-7572
|
|
573
|
-
type.caster.prototype.$__setSchema(type.schema);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
const discriminators = schema.discriminators;
|
|
578
|
-
if (discriminators == null) {
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
const applyPluginsToDiscriminators = get(this,
|
|
574
|
+
options = options || {};
|
|
575
|
+
options.applyPluginsToDiscriminators = get(this,
|
|
583
576
|
'options.applyPluginsToDiscriminators', false);
|
|
584
|
-
|
|
585
|
-
const keys = Object.keys(discriminators);
|
|
586
|
-
for (let i = 0; i < keys.length; ++i) {
|
|
587
|
-
const discriminatorKey = keys[i];
|
|
588
|
-
const discriminatorSchema = discriminators[discriminatorKey];
|
|
589
|
-
|
|
590
|
-
this._applyPlugins(discriminatorSchema, { skipTopLevel: !applyPluginsToDiscriminators });
|
|
591
|
-
}
|
|
577
|
+
applyPlugins(schema, this.plugins, options, '$globalPluginsApplied');
|
|
592
578
|
};
|
|
593
579
|
|
|
594
580
|
/**
|
package/lib/internal.js
CHANGED
package/lib/model.js
CHANGED
|
@@ -11,6 +11,7 @@ const DocumentNotFoundError = require('./error').DocumentNotFoundError;
|
|
|
11
11
|
const DivergentArrayError = require('./error').DivergentArrayError;
|
|
12
12
|
const Error = require('./error');
|
|
13
13
|
const EventEmitter = require('events').EventEmitter;
|
|
14
|
+
const MongooseBuffer = require('./types/buffer');
|
|
14
15
|
const OverwriteModelError = require('./error').OverwriteModelError;
|
|
15
16
|
const PromiseProvider = require('./promise_provider');
|
|
16
17
|
const Query = require('./query');
|
|
@@ -21,6 +22,7 @@ const ParallelSaveError = require('./error').ParallelSaveError;
|
|
|
21
22
|
const applyQueryMiddleware = require('./helpers/query/applyQueryMiddleware');
|
|
22
23
|
const applyHooks = require('./helpers/model/applyHooks');
|
|
23
24
|
const applyMethods = require('./helpers/model/applyMethods');
|
|
25
|
+
const applyStaticHooks = require('./helpers/model/applyStaticHooks');
|
|
24
26
|
const applyStatics = require('./helpers/model/applyStatics');
|
|
25
27
|
const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
|
|
26
28
|
const assignVals = require('./helpers/populate/assignVals');
|
|
@@ -689,7 +691,7 @@ Model.prototype.$__delta = function() {
|
|
|
689
691
|
} else if (value._path && value._atomics) {
|
|
690
692
|
// arrays and other custom types (support plugins etc)
|
|
691
693
|
handleAtomics(this, where, delta, data, value);
|
|
692
|
-
} else if (value.
|
|
694
|
+
} else if (value[MongooseBuffer.pathSymbol] && Buffer.isBuffer(value)) {
|
|
693
695
|
// MongooseBuffer
|
|
694
696
|
value = value.toObject();
|
|
695
697
|
operand(this, where, delta, data, value);
|
|
@@ -905,6 +907,37 @@ Model.prototype.remove = function remove(options, fn) {
|
|
|
905
907
|
|
|
906
908
|
Model.prototype.delete = Model.prototype.remove;
|
|
907
909
|
|
|
910
|
+
/**
|
|
911
|
+
* Removes this document from the db. Equivalent to `.remove()`.
|
|
912
|
+
*
|
|
913
|
+
* ####Example:
|
|
914
|
+
* product = await product.deleteOne();
|
|
915
|
+
* await Product.findById(product._id); // null
|
|
916
|
+
*
|
|
917
|
+
* @param {function(err,product)} [fn] optional callback
|
|
918
|
+
* @return {Promise} Promise
|
|
919
|
+
* @api public
|
|
920
|
+
*/
|
|
921
|
+
|
|
922
|
+
Model.prototype.deleteOne = function deleteOne(options, fn) {
|
|
923
|
+
if (typeof options === 'function') {
|
|
924
|
+
fn = options;
|
|
925
|
+
options = undefined;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
if (!options) {
|
|
929
|
+
options = {};
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
if (fn) {
|
|
933
|
+
fn = this.constructor.$wrapCallback(fn);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return utils.promiseOrCallback(fn, cb => {
|
|
937
|
+
this.$__deleteOne(options, cb);
|
|
938
|
+
}, this.constructor.events);
|
|
939
|
+
};
|
|
940
|
+
|
|
908
941
|
/*!
|
|
909
942
|
* ignore
|
|
910
943
|
*/
|
|
@@ -940,6 +973,12 @@ Model.prototype.$__remove = function $__remove(options, cb) {
|
|
|
940
973
|
});
|
|
941
974
|
};
|
|
942
975
|
|
|
976
|
+
/*!
|
|
977
|
+
* ignore
|
|
978
|
+
*/
|
|
979
|
+
|
|
980
|
+
Model.prototype.$__deleteOne = Model.prototype.$__remove;
|
|
981
|
+
|
|
943
982
|
/**
|
|
944
983
|
* Returns another Model instance.
|
|
945
984
|
*
|
|
@@ -1081,14 +1120,6 @@ Model.init = function init(callback) {
|
|
|
1081
1120
|
return this.$init;
|
|
1082
1121
|
}
|
|
1083
1122
|
|
|
1084
|
-
// If `dropDatabase()` is called, this model's collection will not be
|
|
1085
|
-
// init-ed. It is sufficiently common to call `dropDatabase()` after
|
|
1086
|
-
// `mongoose.connect()` but before creating models that we want to
|
|
1087
|
-
// support this. See gh-6967
|
|
1088
|
-
this.db.$internalEmitter.once('dropDatabase', () => {
|
|
1089
|
-
delete this.$init;
|
|
1090
|
-
});
|
|
1091
|
-
|
|
1092
1123
|
const Promise = PromiseProvider.get();
|
|
1093
1124
|
const autoIndex = this.schema.options.autoIndex == null ?
|
|
1094
1125
|
this.db.config.autoIndex :
|
|
@@ -2803,6 +2834,20 @@ Model.create = function create(doc, options, callback) {
|
|
|
2803
2834
|
} else {
|
|
2804
2835
|
args = utils.args(arguments);
|
|
2805
2836
|
}
|
|
2837
|
+
|
|
2838
|
+
if (args.length === 2 &&
|
|
2839
|
+
args[0] != null &&
|
|
2840
|
+
args[1] != null &&
|
|
2841
|
+
args[0].session == null &&
|
|
2842
|
+
last.session != null &&
|
|
2843
|
+
last.session.constructor.name === 'ClientSession' &&
|
|
2844
|
+
!this.schema.path('session')) {
|
|
2845
|
+
// Probably means the user is running into the common mistake of trying
|
|
2846
|
+
// to use a spread to specify options, see gh-7535
|
|
2847
|
+
console.warn('WARNING: to pass a `session` to `Model.create()` in ' +
|
|
2848
|
+
'Mongoose, you **must** pass an array as the first argument. See: ' +
|
|
2849
|
+
'https://mongoosejs.com/docs/api.html#model_Model.create');
|
|
2850
|
+
}
|
|
2806
2851
|
}
|
|
2807
2852
|
|
|
2808
2853
|
if (cb) {
|
|
@@ -2844,6 +2889,11 @@ Model.create = function create(doc, options, callback) {
|
|
|
2844
2889
|
}
|
|
2845
2890
|
}
|
|
2846
2891
|
|
|
2892
|
+
// Make sure session is available in middleware
|
|
2893
|
+
if (options.session != null) {
|
|
2894
|
+
toSave.$session(options.session);
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2847
2897
|
toSave.save(options, callbackWrapper);
|
|
2848
2898
|
});
|
|
2849
2899
|
});
|
|
@@ -3118,7 +3168,32 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3118
3168
|
* console.log(res.insertedCount, res.modifiedCount, res.deletedCount);
|
|
3119
3169
|
* });
|
|
3120
3170
|
*
|
|
3171
|
+
* The [supported operations](https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/#db.collection.bulkWrite) are:
|
|
3172
|
+
*
|
|
3173
|
+
* - `insertOne`
|
|
3174
|
+
* - `updateOne`
|
|
3175
|
+
* - `updateMany`
|
|
3176
|
+
* - `deleteOne`
|
|
3177
|
+
* - `deleteMany`
|
|
3178
|
+
* - `replaceOne`
|
|
3179
|
+
*
|
|
3121
3180
|
* @param {Array} ops
|
|
3181
|
+
* @param {Object} [ops.insertOne.document] The document to insert
|
|
3182
|
+
* @param {Object} [opts.updateOne.filter] Update the first document that matches this filter
|
|
3183
|
+
* @param {Object} [opts.updateOne.update] An object containing [update operators](https://docs.mongodb.com/manual/reference/operator/update/)
|
|
3184
|
+
* @param {Boolean} [opts.updateOne.upsert=false] If true, insert a doc if none match
|
|
3185
|
+
* @param {Object} [opts.updateOne.collation] The [MongoDB collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) to use
|
|
3186
|
+
* @param {Array} [opts.updateOne.arrayFilters] The [array filters](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html) used in `update`
|
|
3187
|
+
* @param {Object} [opts.updateMany.filter] Update all the documents that match this filter
|
|
3188
|
+
* @param {Object} [opts.updateMany.update] An object containing [update operators](https://docs.mongodb.com/manual/reference/operator/update/)
|
|
3189
|
+
* @param {Boolean} [opts.updateMany.upsert=false] If true, insert a doc if no documents match `filter`
|
|
3190
|
+
* @param {Object} [opts.updateMany.collation] The [MongoDB collation](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-34-collations) to use
|
|
3191
|
+
* @param {Array} [opts.updateMany.arrayFilters] The [array filters](https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html) used in `update`
|
|
3192
|
+
* @param {Object} [opts.deleteOne.filter] Delete the first document that matches this filter
|
|
3193
|
+
* @param {Object} [opts.deleteMany.filter] Delete all documents that match this filter
|
|
3194
|
+
* @param {Object} [opts.replaceOne.filter] Replace the first document that matches this filter
|
|
3195
|
+
* @param {Object} [opts.replaceOne.replacement] The replacement document
|
|
3196
|
+
* @param {Boolean} [opts.replaceOne.upsert=false] If true, insert a doc if no documents match `filter`
|
|
3122
3197
|
* @param {Object} [options]
|
|
3123
3198
|
* @param {Boolean} [options.ordered=true] If true, execute writes in order and stop at the first error. If false, execute writes in parallel and continue until all writes have either succeeded or errored.
|
|
3124
3199
|
* @param {ClientSession} [options.session=null] The session associated with this bulk write. See [transactions docs](/docs/transactions.html).
|
|
@@ -3255,9 +3330,17 @@ Model.hydrate = function(obj) {
|
|
|
3255
3330
|
* @param {Object} conditions
|
|
3256
3331
|
* @param {Object} doc
|
|
3257
3332
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
|
|
3333
|
+
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
|
|
3334
|
+
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
3335
|
+
* @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
|
|
3336
|
+
* @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
|
|
3337
|
+
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
|
|
3338
|
+
* @param {Function} [callback] params are (error, writeOpResult)
|
|
3258
3339
|
* @param {Function} [callback]
|
|
3259
3340
|
* @return {Query}
|
|
3260
3341
|
* @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
|
|
3342
|
+
* @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
|
|
3343
|
+
* @see Query docs https://mongoosejs.com/docs/queries.html
|
|
3261
3344
|
* @api public
|
|
3262
3345
|
*/
|
|
3263
3346
|
|
|
@@ -3286,10 +3369,15 @@ Model.update = function update(conditions, doc, options, callback) {
|
|
|
3286
3369
|
* @param {Object} doc
|
|
3287
3370
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
|
|
3288
3371
|
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
|
|
3372
|
+
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
3373
|
+
* @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
|
|
3289
3374
|
* @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
|
|
3290
|
-
* @param {
|
|
3375
|
+
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
|
|
3376
|
+
* @param {Function} [callback] `function(error, res) {}` where `res` has 3 properties: `n`, `nModified`, `ok`.
|
|
3291
3377
|
* @return {Query}
|
|
3378
|
+
* @see Query docs https://mongoosejs.com/docs/queries.html
|
|
3292
3379
|
* @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
|
|
3380
|
+
* @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
|
|
3293
3381
|
* @api public
|
|
3294
3382
|
*/
|
|
3295
3383
|
|
|
@@ -3317,10 +3405,15 @@ Model.updateMany = function updateMany(conditions, doc, options, callback) {
|
|
|
3317
3405
|
* @param {Object} doc
|
|
3318
3406
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
|
|
3319
3407
|
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
|
|
3408
|
+
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
3409
|
+
* @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
|
|
3320
3410
|
* @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
|
|
3321
|
-
* @param {
|
|
3411
|
+
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
|
|
3412
|
+
* @param {Function} [callback] params are (error, writeOpResult)
|
|
3322
3413
|
* @return {Query}
|
|
3414
|
+
* @see Query docs https://mongoosejs.com/docs/queries.html
|
|
3323
3415
|
* @see MongoDB docs https://docs.mongodb.com/manual/reference/command/update/#update-command-output
|
|
3416
|
+
* @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
|
|
3324
3417
|
* @api public
|
|
3325
3418
|
*/
|
|
3326
3419
|
|
|
@@ -3345,8 +3438,14 @@ Model.updateOne = function updateOne(conditions, doc, options, callback) {
|
|
|
3345
3438
|
* @param {Object} doc
|
|
3346
3439
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](http://mongoosejs.com/docs/api.html#query_Query-setOptions)
|
|
3347
3440
|
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
|
|
3441
|
+
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
3442
|
+
* @param {Object} [options.writeConcern=null] sets the [write concern](https://docs.mongodb.com/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](/docs/guide.html#writeConcern)
|
|
3348
3443
|
* @param {Boolean} [options.omitUndefined=false] If true, delete any properties whose value is `undefined` when casting an update. In other words, if this is set, Mongoose will delete `baz` from the update in `Model.updateOne({}, { foo: 'bar', baz: undefined })` before sending the update to the server.
|
|
3349
|
-
* @param {
|
|
3444
|
+
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
|
|
3445
|
+
* @param {Function} [callback] `function(error, res) {}` where `res` has 3 properties: `n`, `nModified`, `ok`.
|
|
3446
|
+
* @return {Query}
|
|
3447
|
+
* @see Query docs https://mongoosejs.com/docs/queries.html
|
|
3448
|
+
* @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
|
|
3350
3449
|
* @return {Query}
|
|
3351
3450
|
* @api public
|
|
3352
3451
|
*/
|
|
@@ -3728,6 +3827,7 @@ Model.geoSearch = function(conditions, options, callback) {
|
|
|
3728
3827
|
* @param {boolean} [options.retainNullValues=false] by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
|
|
3729
3828
|
* @param {boolean} [options.getters=false] if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](/docs/schematypes.html#schematype-options).
|
|
3730
3829
|
* @param {boolean} [options.clone=false] When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
|
|
3830
|
+
* @param {Object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://docs.mongodb.com/manual/tutorial/query-documents/), or a function that returns a filter object.
|
|
3731
3831
|
* @param {Function} [callback(err,doc)] Optional callback, executed upon completion. Receives `err` and the `doc(s)`.
|
|
3732
3832
|
* @return {Promise}
|
|
3733
3833
|
* @api public
|
|
@@ -3827,15 +3927,7 @@ function populate(model, docs, options, callback) {
|
|
|
3827
3927
|
for (let i = 0; i < len; ++i) {
|
|
3828
3928
|
mod = modelsMap[i];
|
|
3829
3929
|
select = mod.options.select;
|
|
3830
|
-
|
|
3831
|
-
if (mod.options.match) {
|
|
3832
|
-
match = utils.object.shallowCopy(mod.options.match);
|
|
3833
|
-
} else if (get(mod, 'options.options.match')) {
|
|
3834
|
-
match = utils.object.shallowCopy(mod.options.options.match);
|
|
3835
|
-
delete mod.options.options.match;
|
|
3836
|
-
} else {
|
|
3837
|
-
match = {};
|
|
3838
|
-
}
|
|
3930
|
+
match = _formatMatch(mod.match);
|
|
3839
3931
|
|
|
3840
3932
|
let ids = utils.array.flatten(mod.ids, flatten);
|
|
3841
3933
|
ids = utils.array.unique(ids);
|
|
@@ -3852,10 +3944,16 @@ function populate(model, docs, options, callback) {
|
|
|
3852
3944
|
match[foreignField] = { $in: ids };
|
|
3853
3945
|
}
|
|
3854
3946
|
} else {
|
|
3855
|
-
|
|
3947
|
+
const $or = [];
|
|
3948
|
+
if (Array.isArray(match.$or)) {
|
|
3949
|
+
match.$and = [{ $or: match.$or }, { $or: $or }];
|
|
3950
|
+
delete match.$or;
|
|
3951
|
+
} else {
|
|
3952
|
+
match.$or = $or;
|
|
3953
|
+
}
|
|
3856
3954
|
for (const foreignField of mod.foreignField) {
|
|
3857
3955
|
if (foreignField !== '_id' || !match['_id']) {
|
|
3858
|
-
|
|
3956
|
+
$or.push({ [foreignField]: { $in: ids } });
|
|
3859
3957
|
}
|
|
3860
3958
|
}
|
|
3861
3959
|
}
|
|
@@ -4029,11 +4127,27 @@ function populate(model, docs, options, callback) {
|
|
|
4029
4127
|
allOptions: mod,
|
|
4030
4128
|
lean: lean,
|
|
4031
4129
|
virtual: mod.virtual,
|
|
4032
|
-
count: mod.count
|
|
4130
|
+
count: mod.count,
|
|
4131
|
+
match: mod.match
|
|
4033
4132
|
});
|
|
4034
4133
|
}
|
|
4035
4134
|
}
|
|
4036
4135
|
|
|
4136
|
+
/*!
|
|
4137
|
+
* Format `mod.match` given that it may be an array that we need to $or if
|
|
4138
|
+
* the client has multiple docs with match functions
|
|
4139
|
+
*/
|
|
4140
|
+
|
|
4141
|
+
function _formatMatch(match) {
|
|
4142
|
+
if (Array.isArray(match)) {
|
|
4143
|
+
if (match.length > 1) {
|
|
4144
|
+
return { $or: [].concat(match.map(m => Object.assign({}, m))) };
|
|
4145
|
+
}
|
|
4146
|
+
return Object.assign({}, match[0]);
|
|
4147
|
+
}
|
|
4148
|
+
return Object.assign({}, match);
|
|
4149
|
+
}
|
|
4150
|
+
|
|
4037
4151
|
function getModelsMapForPopulate(model, docs, options) {
|
|
4038
4152
|
let i;
|
|
4039
4153
|
let doc;
|
|
@@ -4187,6 +4301,15 @@ function getModelsMapForPopulate(model, docs, options) {
|
|
|
4187
4301
|
const id = String(utils.getValue(foreignField, doc));
|
|
4188
4302
|
options._docs[id] = Array.isArray(ret) ? ret.slice() : ret;
|
|
4189
4303
|
|
|
4304
|
+
let match = get(options, 'match', null) ||
|
|
4305
|
+
get(currentOptions, 'match', null) ||
|
|
4306
|
+
get(options, 'virtual.options.options.match', null);
|
|
4307
|
+
|
|
4308
|
+
const hasMatchFunction = typeof match === 'function';
|
|
4309
|
+
if (hasMatchFunction) {
|
|
4310
|
+
match = match.call(doc, doc);
|
|
4311
|
+
}
|
|
4312
|
+
|
|
4190
4313
|
let k = modelNames.length;
|
|
4191
4314
|
while (k--) {
|
|
4192
4315
|
modelName = modelNames[k];
|
|
@@ -4225,6 +4348,7 @@ function getModelsMapForPopulate(model, docs, options) {
|
|
|
4225
4348
|
available[modelName] = {
|
|
4226
4349
|
model: Model,
|
|
4227
4350
|
options: currentOptions,
|
|
4351
|
+
match: hasMatchFunction ? [match] : match,
|
|
4228
4352
|
docs: [doc],
|
|
4229
4353
|
ids: [ids],
|
|
4230
4354
|
allIds: [ret],
|
|
@@ -4242,6 +4366,9 @@ function getModelsMapForPopulate(model, docs, options) {
|
|
|
4242
4366
|
available[modelName].docs.push(doc);
|
|
4243
4367
|
available[modelName].ids.push(ids);
|
|
4244
4368
|
available[modelName].allIds.push(ret);
|
|
4369
|
+
if (hasMatchFunction) {
|
|
4370
|
+
available[modelName].match.push(match);
|
|
4371
|
+
}
|
|
4245
4372
|
}
|
|
4246
4373
|
}
|
|
4247
4374
|
}
|
|
@@ -4360,7 +4487,7 @@ function convertTo_id(val) {
|
|
|
4360
4487
|
}
|
|
4361
4488
|
}
|
|
4362
4489
|
if (val.isMongooseArray && val._schema) {
|
|
4363
|
-
return val._schema.cast(val, val
|
|
4490
|
+
return val._schema.cast(val, val.$parent());
|
|
4364
4491
|
}
|
|
4365
4492
|
|
|
4366
4493
|
return [].concat(val);
|
|
@@ -4469,7 +4596,8 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
|
|
|
4469
4596
|
|
|
4470
4597
|
const collectionOptions = {
|
|
4471
4598
|
bufferCommands: bufferCommands,
|
|
4472
|
-
capped: schema.options.capped
|
|
4599
|
+
capped: schema.options.capped,
|
|
4600
|
+
Promise: model.base.Promise
|
|
4473
4601
|
};
|
|
4474
4602
|
|
|
4475
4603
|
model.prototype.collection = connection.collection(
|
|
@@ -4482,6 +4610,7 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
|
|
|
4482
4610
|
applyMethods(model, schema);
|
|
4483
4611
|
applyStatics(model, schema);
|
|
4484
4612
|
applyHooks(model, schema);
|
|
4613
|
+
applyStaticHooks(model, schema.s.hooks, schema.statics);
|
|
4485
4614
|
|
|
4486
4615
|
model.schema = model.prototype.schema;
|
|
4487
4616
|
model.collection = model.prototype.collection;
|
|
@@ -4495,13 +4624,6 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
|
|
|
4495
4624
|
applyQueryMiddleware(model.Query, model);
|
|
4496
4625
|
applyQueryMethods(model, schema.query);
|
|
4497
4626
|
|
|
4498
|
-
const kareemOptions = {
|
|
4499
|
-
useErrorHandlers: true,
|
|
4500
|
-
numCallbackParams: 1
|
|
4501
|
-
};
|
|
4502
|
-
model.$__insertMany = model.hooks.createWrapper('insertMany',
|
|
4503
|
-
model.$__insertMany, model, kareemOptions);
|
|
4504
|
-
|
|
4505
4627
|
return model;
|
|
4506
4628
|
};
|
|
4507
4629
|
|