Skip to content

Commit 97d7fae

Browse files
committed
fix(populate): various cleanup for ordered option
Fix Automattic#15210
1 parent 748caea commit 97d7fae

File tree

4 files changed

+12
-18
lines changed

4 files changed

+12
-18
lines changed

lib/document.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4508,6 +4508,8 @@ Document.prototype.equals = function(doc) {
45084508
* @param {Object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
45094509
* @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
45104510
* @param {Object} [options.options=null] Additional options like `limit` and `lean`.
4511+
* @param {Boolean} [options.forceRepopulate=true] Set to `false` to prevent Mongoose from repopulating paths that are already populated
4512+
* @param {Boolean} [options.ordered=false] Set to `true` to execute any populate queries one at a time, as opposed to in parallel. We recommend setting this option to `true` if using transactions, especially if also populating multiple paths or paths with multiple models. MongoDB server does **not** support multiple operations in parallel on a single transaction.
45114513
* @param {Function} [callback] Callback
45124514
* @see population https://mongoosejs.com/docs/populate.html
45134515
* @see Query#select https://mongoosejs.com/docs/api/query.html#Query.prototype.select()
@@ -4525,20 +4527,15 @@ Document.prototype.populate = async function populate() {
45254527
throw new MongooseError('Document.prototype.populate() no longer accepts a callback');
45264528
}
45274529

4528-
let ordered = null;
45294530
if (args.length !== 0) {
45304531
// use hash to remove duplicate paths
45314532
const res = utils.populate.apply(null, args);
4532-
ordered = res.ordered;
45334533
for (const populateOptions of res) {
45344534
pop[populateOptions.path] = populateOptions;
45354535
}
45364536
}
45374537

45384538
const paths = utils.object.vals(pop);
4539-
if (ordered) {
4540-
paths.ordered = ordered;
4541-
}
45424539

45434540
let topLevelModel = this.constructor;
45444541
if (this.$__isNested) {

lib/model.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4258,6 +4258,7 @@ Model.validate = async function validate(obj, pathsOrOptions, context) {
42584258
* @param {Object} [options.options=null] Additional options like `limit` and `lean`.
42594259
* @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
42604260
* @param {Boolean} [options.forceRepopulate=true] Set to `false` to prevent Mongoose from repopulating paths that are already populated
4261+
* @param {Boolean} [options.ordered=false] Set to `true` to execute any populate queries one at a time, as opposed to in parallel. Set this option to `true` if populating multiple paths or paths with multiple models in transactions.
42614262
* @return {Promise}
42624263
* @api public
42634264
*/
@@ -4275,9 +4276,10 @@ Model.populate = async function populate(docs, paths) {
42754276
}
42764277

42774278
// each path has its own query options and must be executed separately
4278-
if (paths.ordered) {
4279+
if (paths.find(p => p.ordered)) {
42794280
// Populate in series, primarily for transactions because MongoDB doesn't support multiple operations on
42804281
// one transaction in parallel.
4282+
// Note that if _any_ path has `ordered`, we make the top-level populate `ordered` as well.
42814283
for (const path of paths) {
42824284
await _populatePath(this, docs, path);
42834285
}

lib/utils.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -523,11 +523,7 @@ exports.populate = function populate(path, select, model, match, options, subPop
523523

524524
if (Array.isArray(path)) {
525525
const singles = makeSingles(path);
526-
const ret = singles.map(o => exports.populate(o)[0]);
527-
if (path.ordered) {
528-
ret.ordered = path.ordered;
529-
}
530-
return ret;
526+
return singles.map(o => exports.populate(o)[0]);
531527
}
532528

533529
if (exports.isObject(path)) {
@@ -617,13 +613,6 @@ function _populateObj(obj) {
617613
ret.push(new PopulateOptions(Object.assign({}, obj, { path: path })));
618614
}
619615

620-
if (obj.ordered) {
621-
ret.ordered = true;
622-
for (const path of ret) {
623-
path.ordered = true;
624-
}
625-
}
626-
627616
return ret;
628617
}
629618

types/populate.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ declare module 'mongoose' {
3939
foreignField?: string;
4040
/** Set to `false` to prevent Mongoose from repopulating paths that are already populated */
4141
forceRepopulate?: boolean;
42+
/**
43+
* Set to `true` to execute any populate queries one at a time, as opposed to in parallel.
44+
* We recommend setting this option to `true` if using transactions, especially if also populating multiple paths or paths with multiple models.
45+
* MongoDB server does **not** support multiple operations in parallel on a single transaction.
46+
*/
47+
ordered?: boolean;
4248
}
4349

4450
interface PopulateOption {

0 commit comments

Comments
 (0)