From 6419a8787f2b4ce2dbaaf143dcfa0cd1feb733e9 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 16 Oct 2023 17:15:01 -0400 Subject: [PATCH] fix(populate): handle multiple spaces when specifying paths to populate using space-delimited paths Fix #13951 --- lib/utils.js | 13 ++++++++----- test/model.populate.test.js | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index b5f3dd4acfc..4fca9502d56 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -31,6 +31,9 @@ exports.isMongooseDocumentArray = isMongooseDocumentArray.isMongooseDocumentArra exports.registerMongooseArray = isMongooseArray.registerMongooseArray; exports.registerMongooseDocumentArray = isMongooseDocumentArray.registerMongooseDocumentArray; +const oneSpaceRE = /\s/; +const manySpaceRE = /\s+/; + /** * Produces a collection name from model `name`. By default, just returns * the model name @@ -572,8 +575,8 @@ exports.populate = function populate(path, select, model, match, options, subPop function makeSingles(arr) { const ret = []; arr.forEach(function(obj) { - if (/[\s]/.test(obj.path)) { - const paths = obj.path.split(' '); + if (oneSpaceRE.test(obj.path)) { + const paths = obj.path.split(manySpaceRE); paths.forEach(function(p) { const copy = Object.assign({}, obj); copy.path = p; @@ -592,9 +595,9 @@ function _populateObj(obj) { if (Array.isArray(obj.populate)) { const ret = []; obj.populate.forEach(function(obj) { - if (/[\s]/.test(obj.path)) { + if (oneSpaceRE.test(obj.path)) { const copy = Object.assign({}, obj); - const paths = copy.path.split(' '); + const paths = copy.path.split(manySpaceRE); paths.forEach(function(p) { copy.path = p; ret.push(exports.populate(copy)[0]); @@ -609,7 +612,7 @@ function _populateObj(obj) { } const ret = []; - const paths = obj.path.split(' '); + const paths = oneSpaceRE.test(obj.path) ? obj.path.split(manySpaceRE) : [obj.path]; if (obj.options != null) { obj.options = clone(obj.options); } diff --git a/test/model.populate.test.js b/test/model.populate.test.js index c1007f69315..00d16d01b6c 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -2819,7 +2819,28 @@ describe('model: populate:', function() { assert.equal(blogposts[0].user.name, 'Fan 1'); assert.equal(blogposts[0].title, 'Test 1'); + }); + + it('handles multiple spaces in between paths to populate (gh-13951)', async function() { + const BlogPost = db.model('BlogPost', new Schema({ + title: String, + user: { type: ObjectId, ref: 'User' }, + fans: [{ type: ObjectId, ref: 'User' }] + })); + const User = db.model('User', new Schema({ name: String })); + + const fans = await User.create([{ name: 'Fan 1' }]); + const posts = [ + { title: 'Test 1', user: fans[0]._id, fans: [fans[0]._id] } + ]; + await BlogPost.create(posts); + const blogPost = await BlogPost. + findOne({ title: 'Test 1' }). + populate('user \t fans'); + assert.equal(blogPost.user.name, 'Fan 1'); + assert.equal(blogPost.fans[0].name, 'Fan 1'); + assert.equal(blogPost.title, 'Test 1'); }); it('maps results back to correct document (gh-1444)', async function() {