Skip to content

Commit 6aaddb3

Browse files
committed
fix(cursor): correctly populate in batches when batchSize is set
Fix #11509 Re: #9365
1 parent 1f109ea commit 6aaddb3

File tree

4 files changed

+94
-97
lines changed

4 files changed

+94
-97
lines changed

lib/cursor/QueryCursor.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,8 @@ function _nextDoc(ctx, doc, pop, callback) {
472472
});
473473
}
474474

475-
ctx.query._completeOne(doc, null, (err, doc) => {
475+
const { model, _fields, _userProvidedFields, options } = ctx.query;
476+
helpers.createModelAndInit(model, doc, _fields, _userProvidedFields, options, pop, (err, doc) => {
476477
if (err != null) {
477478
return callback(err);
478479
}

lib/query.js

+2-11
Original file line numberDiff line numberDiff line change
@@ -3168,23 +3168,14 @@ Query.prototype._deleteMany = wrapThunk(function(callback) {
31683168
*/
31693169

31703170
function completeOne(model, doc, res, options, fields, userProvidedFields, pop, callback) {
3171-
const opts = pop ?
3172-
{ populated: pop }
3173-
: undefined;
3174-
31753171
if (options.rawResult && doc == null) {
31763172
_init(null);
31773173
return null;
31783174
}
31793175

3180-
const casted = helpers.createModel(model, doc, fields, userProvidedFields, options);
3181-
try {
3182-
casted.$init(doc, opts, _init);
3183-
} catch (error) {
3184-
_init(error);
3185-
}
3176+
helpers.createModelAndInit(model, doc, fields, userProvidedFields, options, pop, _init);
31863177

3187-
function _init(err) {
3178+
function _init(err, casted) {
31883179
if (err) {
31893180
return immediate(() => callback(err));
31903181
}

lib/queryhelpers.js

+17
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,23 @@ exports.createModel = function createModel(model, doc, fields, userProvidedField
123123
return new model(undefined, fields, _opts);
124124
};
125125

126+
/*!
127+
* ignore
128+
*/
129+
130+
exports.createModelAndInit = function createModelAndInit(model, doc, fields, userProvidedFields, options, populatedIds, callback) {
131+
const initOpts = populatedIds ?
132+
{ populated: populatedIds } :
133+
undefined;
134+
135+
const casted = exports.createModel(model, doc, fields, userProvidedFields, options);
136+
try {
137+
casted.$init(doc, initOpts, callback);
138+
} catch (error) {
139+
callback(error, casted);
140+
}
141+
};
142+
126143
/*!
127144
* ignore
128145
*/

test/query.cursor.test.js

+73-85
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,20 @@ describe('QueryCursor', function() {
108108
});
109109

110110
describe('with populate', function() {
111+
let populateCalls = 0;
112+
111113
const bandSchema = new Schema({
112114
name: String,
113115
members: [{ type: mongoose.Schema.ObjectId, ref: 'Person' }]
114116
});
115117
const personSchema = new Schema({
116118
name: String
117119
});
120+
personSchema.pre('find', () => { ++populateCalls; });
118121

119122
let Band;
120123

121-
beforeEach(function(done) {
124+
beforeEach(async function() {
122125
const Person = db.model('Person', personSchema);
123126
Band = db.model('Band', bandSchema);
124127

@@ -131,96 +134,81 @@ describe('QueryCursor', function() {
131134
{ name: 'Thom Yorke' },
132135
{ name: 'Billy Corgan' }
133136
];
134-
Person.create(people, function(error, docs) {
135-
assert.ifError(error);
136-
const bands = [
137-
{ name: 'Guns N\' Roses', members: [docs[0], docs[1]] },
138-
{ name: 'Motley Crue', members: [docs[2], docs[3]] },
139-
{ name: 'Nine Inch Nails', members: [docs[4]] },
140-
{ name: 'Radiohead', members: [docs[5]] },
141-
{ name: 'The Smashing Pumpkins', members: [docs[6]] }
142-
];
143-
Band.create(bands, function(error) {
144-
assert.ifError(error);
145-
done();
146-
});
147-
});
137+
const docs = await Person.create(people);
138+
139+
const bands = [
140+
{ name: 'Guns N\' Roses', members: [docs[0], docs[1]] },
141+
{ name: 'Motley Crue', members: [docs[2], docs[3]] },
142+
{ name: 'Nine Inch Nails', members: [docs[4]] },
143+
{ name: 'Radiohead', members: [docs[5]] },
144+
{ name: 'The Smashing Pumpkins', members: [docs[6]] }
145+
];
146+
await Band.create(bands);
148147
});
149148

150-
it('with populate without specify batchSize', function(done) {
151-
const cursor =
152-
Band.find().sort({ name: 1 }).populate('members').cursor();
153-
cursor.next(function(error, doc) {
154-
assert.ifError(error);
155-
assert.equal(doc.name, 'Guns N\' Roses');
156-
assert.equal(doc.members.length, 2);
157-
assert.equal(doc.members[0].name, 'Axl Rose');
158-
assert.equal(doc.members[1].name, 'Slash');
159-
cursor.next(function(error, doc) {
160-
assert.ifError(error);
161-
assert.equal(doc.name, 'Motley Crue');
162-
assert.equal(doc.members.length, 2);
163-
assert.equal(doc.members[0].name, 'Nikki Sixx');
164-
assert.equal(doc.members[1].name, 'Vince Neil');
165-
cursor.next(function(error, doc) {
166-
assert.ifError(error);
167-
assert.equal(doc.name, 'Nine Inch Nails');
168-
assert.equal(doc.members.length, 1);
169-
assert.equal(doc.members[0].name, 'Trent Reznor');
170-
cursor.next(function(error, doc) {
171-
assert.ifError(error);
172-
assert.equal(doc.name, 'Radiohead');
173-
assert.equal(doc.members.length, 1);
174-
assert.equal(doc.members[0].name, 'Thom Yorke');
175-
cursor.next(function(error, doc) {
176-
assert.ifError(error);
177-
assert.equal(doc.name, 'The Smashing Pumpkins');
178-
assert.equal(doc.members.length, 1);
179-
assert.equal(doc.members[0].name, 'Billy Corgan');
180-
done();
181-
});
182-
});
183-
});
184-
});
185-
});
149+
it('with populate without specify batchSize', async function() {
150+
const cursor = Band.find().sort({ name: 1 }).populate('members').cursor();
151+
152+
let doc = await cursor.next();
153+
assert.equal(doc.name, 'Guns N\' Roses');
154+
assert.equal(doc.members.length, 2);
155+
assert.equal(doc.members[0].name, 'Axl Rose');
156+
assert.equal(doc.members[1].name, 'Slash');
157+
158+
doc = await cursor.next();
159+
assert.equal(doc.name, 'Motley Crue');
160+
assert.equal(doc.members.length, 2);
161+
assert.equal(doc.members[0].name, 'Nikki Sixx');
162+
assert.equal(doc.members[1].name, 'Vince Neil');
163+
164+
doc = await cursor.next();
165+
assert.equal(doc.name, 'Nine Inch Nails');
166+
assert.equal(doc.members.length, 1);
167+
assert.equal(doc.members[0].name, 'Trent Reznor');
168+
169+
doc = await cursor.next();
170+
assert.equal(doc.name, 'Radiohead');
171+
assert.equal(doc.members.length, 1);
172+
assert.equal(doc.members[0].name, 'Thom Yorke');
173+
174+
doc = await cursor.next();
175+
assert.equal(doc.name, 'The Smashing Pumpkins');
176+
assert.equal(doc.members.length, 1);
177+
assert.equal(doc.members[0].name, 'Billy Corgan');
186178
});
187179

188-
it('with populate using custom batchSize', function(done) {
180+
it('with populate using custom batchSize', async function() {
181+
populateCalls = 0;
189182
const cursor =
190183
Band.find().sort({ name: 1 }).populate('members').batchSize(3).cursor();
191-
cursor.next(function(error, doc) {
192-
assert.ifError(error);
193-
assert.equal(doc.name, 'Guns N\' Roses');
194-
assert.equal(doc.members.length, 2);
195-
assert.equal(doc.members[0].name, 'Axl Rose');
196-
assert.equal(doc.members[1].name, 'Slash');
197-
cursor.next(function(error, doc) {
198-
assert.ifError(error);
199-
assert.equal(doc.name, 'Motley Crue');
200-
assert.equal(doc.members.length, 2);
201-
assert.equal(doc.members[0].name, 'Nikki Sixx');
202-
assert.equal(doc.members[1].name, 'Vince Neil');
203-
cursor.next(function(error, doc) {
204-
assert.ifError(error);
205-
assert.equal(doc.name, 'Nine Inch Nails');
206-
assert.equal(doc.members.length, 1);
207-
assert.equal(doc.members[0].name, 'Trent Reznor');
208-
cursor.next(function(error, doc) {
209-
assert.ifError(error);
210-
assert.equal(doc.name, 'Radiohead');
211-
assert.equal(doc.members.length, 1);
212-
assert.equal(doc.members[0].name, 'Thom Yorke');
213-
cursor.next(function(error, doc) {
214-
assert.ifError(error);
215-
assert.equal(doc.name, 'The Smashing Pumpkins');
216-
assert.equal(doc.members.length, 1);
217-
assert.equal(doc.members[0].name, 'Billy Corgan');
218-
done();
219-
});
220-
});
221-
});
222-
});
223-
});
184+
185+
let doc = await cursor.next();
186+
assert.equal(doc.name, 'Guns N\' Roses');
187+
assert.equal(doc.members.length, 2);
188+
assert.equal(doc.members[0].name, 'Axl Rose');
189+
assert.equal(doc.members[1].name, 'Slash');
190+
191+
doc = await cursor.next();
192+
assert.equal(doc.name, 'Motley Crue');
193+
assert.equal(doc.members.length, 2);
194+
assert.equal(doc.members[0].name, 'Nikki Sixx');
195+
assert.equal(doc.members[1].name, 'Vince Neil');
196+
197+
doc = await cursor.next();
198+
assert.equal(doc.name, 'Nine Inch Nails');
199+
assert.equal(doc.members.length, 1);
200+
assert.equal(doc.members[0].name, 'Trent Reznor');
201+
202+
doc = await cursor.next();
203+
assert.equal(doc.members.length, 1);
204+
assert.equal(doc.members[0].name, 'Thom Yorke');
205+
206+
doc = await cursor.next();
207+
assert.equal(doc.name, 'The Smashing Pumpkins');
208+
assert.equal(doc.members.length, 1);
209+
assert.equal(doc.members[0].name, 'Billy Corgan');
210+
211+
assert.equal(populateCalls, 2);
224212
});
225213
});
226214

0 commit comments

Comments
 (0)