Automattic / Automattic/mongoose

Populating virtuals with count: true fires a 'find' query instead of 'countDocuments' query

Open
#8,121 5 comments 0 reactions 0 assignees View on GitHub
performance
Dominant language
JavaScript
Stars
27.5k
Forks
4k
Avg merge
2d 7h
Merged PRs (30d)
35

Description

**Do you want to request a *feature* or report a *bug*?**
I want to suggest an optimisation for an existing feature.

**What is the current behavior?**
Here is the script that I'm using
```js

const mongoose = require('mongoose');
mongoose.Promise = global.Promise;

mongoose.connect('mongodb://localhost:27017', { dbName: 'test-db', useNewUrlParser: true }, function (error) {
if (error) {
console.log('Error in mongo connection', error);
} else {
console.log('Mongo connection established');
}
});
mongoose.set('debug', true);

const PersonSchema = new mongoose.Schema({
name: String,
band: String,
});
let modelPerson = mongoose.model('person', PersonSchema);

const BandSchema = new mongoose.Schema({
name: String
}, { toJSON: { virtuals: true } });
BandSchema.virtual('numMembers', {
ref: 'person',
localField: 'name',
foreignField: 'band',
count: true
});
let modelBand = mongoose.model('band', BandSchema);

let main = async () => {
await modelPerson.insertMany([{ name: 'P1', band: 'B1' }, { name: 'P2', band: 'B1' }]);
await modelBand.create({ name: 'B1' });

let band = await modelBand.findOne({ name: 'B1' }).populate('numMembers');
console.log(band.numMembers);

};

main();
```

In the findOne query for modelBand, populating 'numMembers' fires a find query on modelPerson instead of a simple countDocuments query. This is hghly inefficient considering the count can go well above 1000 in many cases. Actually fetching all those documents will reduce the response time and consume more bandwidth.

In this case, since all we really need is a count of those documents, a countDocuments query is a perfect fit here.

**What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.**
Node.js: 8.10
MongoDb: 4.0.4
Mongoose: 5.6.11

Contributor guide

Open the contributing guide

Research direction

Start with the modelBand.findOne().populate('numMembers') reproduction and trace virtual population for the count: true option. Verify the current query against modelPerson, then add coverage showing that population uses countDocuments and returns the member count without fetching all matching documents.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, mongodb, nodejs
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.