Skip to content

Commit

Permalink
fix(cursor): correctly populate in batches when batchSize is set
Browse files Browse the repository at this point in the history
Fix #11509
Re: #9365
  • Loading branch information
vkarpov15 committed Mar 16, 2022
1 parent 1f109ea commit 6aaddb3
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 97 deletions.
3 changes: 2 additions & 1 deletion lib/cursor/QueryCursor.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,8 @@ function _nextDoc(ctx, doc, pop, callback) {
});
}

ctx.query._completeOne(doc, null, (err, doc) => {
const { model, _fields, _userProvidedFields, options } = ctx.query;
helpers.createModelAndInit(model, doc, _fields, _userProvidedFields, options, pop, (err, doc) => {
if (err != null) {
return callback(err);
}
Expand Down
13 changes: 2 additions & 11 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -3168,23 +3168,14 @@ Query.prototype._deleteMany = wrapThunk(function(callback) {
*/

function completeOne(model, doc, res, options, fields, userProvidedFields, pop, callback) {
const opts = pop ?
{ populated: pop }
: undefined;

if (options.rawResult && doc == null) {
_init(null);
return null;
}

const casted = helpers.createModel(model, doc, fields, userProvidedFields, options);
try {
casted.$init(doc, opts, _init);
} catch (error) {
_init(error);
}
helpers.createModelAndInit(model, doc, fields, userProvidedFields, options, pop, _init);

function _init(err) {
function _init(err, casted) {
if (err) {
return immediate(() => callback(err));
}
Expand Down
17 changes: 17 additions & 0 deletions lib/queryhelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,23 @@ exports.createModel = function createModel(model, doc, fields, userProvidedField
return new model(undefined, fields, _opts);
};

/*!
* ignore
*/

exports.createModelAndInit = function createModelAndInit(model, doc, fields, userProvidedFields, options, populatedIds, callback) {
const initOpts = populatedIds ?
{ populated: populatedIds } :
undefined;

const casted = exports.createModel(model, doc, fields, userProvidedFields, options);
try {
casted.$init(doc, initOpts, callback);
} catch (error) {
callback(error, casted);
}
};

/*!
* ignore
*/
Expand Down
158 changes: 73 additions & 85 deletions test/query.cursor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,20 @@ describe('QueryCursor', function() {
});

describe('with populate', function() {
let populateCalls = 0;

const bandSchema = new Schema({
name: String,
members: [{ type: mongoose.Schema.ObjectId, ref: 'Person' }]
});
const personSchema = new Schema({
name: String
});
personSchema.pre('find', () => { ++populateCalls; });

let Band;

beforeEach(function(done) {
beforeEach(async function() {
const Person = db.model('Person', personSchema);
Band = db.model('Band', bandSchema);

Expand All @@ -131,96 +134,81 @@ describe('QueryCursor', function() {
{ name: 'Thom Yorke' },
{ name: 'Billy Corgan' }
];
Person.create(people, function(error, docs) {
assert.ifError(error);
const bands = [
{ name: 'Guns N\' Roses', members: [docs[0], docs[1]] },
{ name: 'Motley Crue', members: [docs[2], docs[3]] },
{ name: 'Nine Inch Nails', members: [docs[4]] },
{ name: 'Radiohead', members: [docs[5]] },
{ name: 'The Smashing Pumpkins', members: [docs[6]] }
];
Band.create(bands, function(error) {
assert.ifError(error);
done();
});
});
const docs = await Person.create(people);

const bands = [
{ name: 'Guns N\' Roses', members: [docs[0], docs[1]] },
{ name: 'Motley Crue', members: [docs[2], docs[3]] },
{ name: 'Nine Inch Nails', members: [docs[4]] },
{ name: 'Radiohead', members: [docs[5]] },
{ name: 'The Smashing Pumpkins', members: [docs[6]] }
];
await Band.create(bands);
});

it('with populate without specify batchSize', function(done) {
const cursor =
Band.find().sort({ name: 1 }).populate('members').cursor();
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'Guns N\' Roses');
assert.equal(doc.members.length, 2);
assert.equal(doc.members[0].name, 'Axl Rose');
assert.equal(doc.members[1].name, 'Slash');
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'Motley Crue');
assert.equal(doc.members.length, 2);
assert.equal(doc.members[0].name, 'Nikki Sixx');
assert.equal(doc.members[1].name, 'Vince Neil');
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'Nine Inch Nails');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Trent Reznor');
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'Radiohead');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Thom Yorke');
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'The Smashing Pumpkins');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Billy Corgan');
done();
});
});
});
});
});
it('with populate without specify batchSize', async function() {
const cursor = Band.find().sort({ name: 1 }).populate('members').cursor();

let doc = await cursor.next();
assert.equal(doc.name, 'Guns N\' Roses');
assert.equal(doc.members.length, 2);
assert.equal(doc.members[0].name, 'Axl Rose');
assert.equal(doc.members[1].name, 'Slash');

doc = await cursor.next();
assert.equal(doc.name, 'Motley Crue');
assert.equal(doc.members.length, 2);
assert.equal(doc.members[0].name, 'Nikki Sixx');
assert.equal(doc.members[1].name, 'Vince Neil');

doc = await cursor.next();
assert.equal(doc.name, 'Nine Inch Nails');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Trent Reznor');

doc = await cursor.next();
assert.equal(doc.name, 'Radiohead');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Thom Yorke');

doc = await cursor.next();
assert.equal(doc.name, 'The Smashing Pumpkins');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Billy Corgan');
});

it('with populate using custom batchSize', function(done) {
it('with populate using custom batchSize', async function() {
populateCalls = 0;
const cursor =
Band.find().sort({ name: 1 }).populate('members').batchSize(3).cursor();
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'Guns N\' Roses');
assert.equal(doc.members.length, 2);
assert.equal(doc.members[0].name, 'Axl Rose');
assert.equal(doc.members[1].name, 'Slash');
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'Motley Crue');
assert.equal(doc.members.length, 2);
assert.equal(doc.members[0].name, 'Nikki Sixx');
assert.equal(doc.members[1].name, 'Vince Neil');
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'Nine Inch Nails');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Trent Reznor');
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'Radiohead');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Thom Yorke');
cursor.next(function(error, doc) {
assert.ifError(error);
assert.equal(doc.name, 'The Smashing Pumpkins');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Billy Corgan');
done();
});
});
});
});
});

let doc = await cursor.next();
assert.equal(doc.name, 'Guns N\' Roses');
assert.equal(doc.members.length, 2);
assert.equal(doc.members[0].name, 'Axl Rose');
assert.equal(doc.members[1].name, 'Slash');

doc = await cursor.next();
assert.equal(doc.name, 'Motley Crue');
assert.equal(doc.members.length, 2);
assert.equal(doc.members[0].name, 'Nikki Sixx');
assert.equal(doc.members[1].name, 'Vince Neil');

doc = await cursor.next();
assert.equal(doc.name, 'Nine Inch Nails');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Trent Reznor');

doc = await cursor.next();
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Thom Yorke');

doc = await cursor.next();
assert.equal(doc.name, 'The Smashing Pumpkins');
assert.equal(doc.members.length, 1);
assert.equal(doc.members[0].name, 'Billy Corgan');

assert.equal(populateCalls, 2);
});
});

Expand Down

0 comments on commit 6aaddb3

Please sign in to comment.