question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Potentially undocumented migration (breaking) change for populating virtuals with no matches, mongoose 5.x returns an empty array, mongoose 6.x returns undefined.

See original GitHub issue

Do you want to request a feature or report a bug?

Possible bug or potentially undocumented breaking change.

What is the current behavior?

Apologies in advance because this seems like something minor. The current behavior is the following - on mongoose 5.x, or version 5.12.14 to be exact, when you are using the Model.populate({ path: '....' }) method, if there are no documents to be found, the query returns an empty array. On Mongoose@latest (6.x+) the same exact query returns undefined instead.

If the current behavior is a bug, please provide the steps to reproduce.

Matches.js

const mongoose = require('mongoose');
const mongooseLeanVirtuals = require('mongoose-lean-virtuals');
const Schema = mongoose.Schema;

const MatchSchema = new Schema(
    {
        _id: { type: Schema.Types.ObjectId, auto: true },
        timestamp: { type: Number, required: true, min: 1577836800000, max: 4102444800000 },
    },
    {
        toObject: {
            virtuals: true
        },
        toJSON: {
            virtuals: true
        }
    }
);

MatchSchema.virtual('predictions', {
    ref: 'predictions',
    localField: '_id',
    foreignField: 'match_id',
    justOne: false,
});

MatchSchema.plugin(mongooseLeanVirtuals);
const Matches = mongoose.model('matches', MatchSchema);

module.exports = Matches;

Predictions.js

const mongoose = require('mongoose');
const mongooseLeanVirtuals = require('mongoose-lean-virtuals');
const Schema = mongoose.Schema;

const PredictionSchema = new Schema(
    {
        _id: { type: Schema.Types.ObjectId, auto: true },
        match_id: { type: Schema.Types.ObjectId, required: true },
    },
    {
        toObject: {
            virtuals: true
        },
        toJSON: {
            virtuals: true
        }
    }
);

PredictionSchema.plugin(mongooseLeanVirtuals);
const Predictions = mongoose.model('predictions', PredictionSchema);

module.exports = Predictions;

Main.js

const mongoose = require('mongoose');
const mongoose_options = {
    autoIndex: true,
    connectTimeoutMS: 10000,
    socketTimeoutMS: 45000,
    family: 4,
    ssl: true
};

const Matches = require('./models/matches');
const Predictions = require('./models/predictions');

(async () => {
    try {
        await mongoose.connect(
            `mongodb+srv://${USER}:${PASS}@${SERVER_ADDR}/${DB_NAME}?retryWrites=true&w=majority`,
            mongoose_options,
        );

        await runTest();

    } catch (error) {
        console.log(error);
    }
})();

const runTest = async () => {
    await Matches.findOneAndUpdate(
        { timestamp: 1577836800000 },
        { timestamp: 1577836800000 },
        { upsert: true }
    );

    const matches = await Matches.find({})
        .populate({ path: 'predictions' })
        .sort({ timestamp: 'desc' })
        .lean({ virtuals: ['predictions'] });

    console.log(matches);
}

What is the expected behavior?

Suppose that there is a match document with a specific mongo _id, but there are no prediction documents to match the populate() query. The code above outputs the following:

// 5.12.14
[
    {
        _id: 6154f33f92736dfa92eda7c9,
        timestamp: 4102444100000,
        predictions: [] // <= this is version 5.x, it returns an empty array.
    },
]
// 6.0.8
[
    {
        _id: new ObjectId("6154f33f92736dfa92eda7c9"),
        timestamp: 4102444100000,
        predictions: undefined // <= this is version 6.x, and it returns undefined instead.
    },
]

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that “latest” is not a version.

Node v16.9.1 Mongoose 5.12.14 and 6.0.8


Anyway, my only small request here is to either document this in the migration guide, or if this is not intended behavior and it’s a bug, then I suppose that I am reporting it now.

Thank you for your time!

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:6

github_iconTop GitHub Comments

1reaction
vkarpov15commented, Nov 11, 2021

@brentmjohnson that is correct, lean() without this package will return undefined rather than empty array if there’s no results.

0reactions
brentmjohnsoncommented, Nov 8, 2021

We ran into this issue as well during our 5 -> 6 migration. In our case we were not using the mongoose-lean-virtuals package and instead statically setting toJSON: { virtuals: true }, toObject: { virtuals: true } at the parent schema level.

The virtual was defined with the default of justOne: false

Can you confirm it is expected behavior that using lean() with populate virtuals (but without the mongoose-lean-virtuals package) will now return undefined rather than an empty array?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Mongoose 5 to 6: Virtual populate lean does not return empty ...
I'm migrating mongoose from 5 to 6 and upon testing I got this issue: ... Mongoose 5 to 6: Virtual populate lean does...
Read more >
Migrating to Mongoose 6
There are several backwards-breaking changes you should be aware of when migrating from Mongoose 5.x to Mongoose 6.x. If you're still on Mongoose...
Read more >
backend/node_modules/mongoose/History.md - Git01Lab
5.8.4 / 2020-01-02. fix(populate): ensure populate virtual gets set to empty array if localField is undefined in the database #8455; fix( ...
Read more >
Mongoose populate() returns empty array with no errors
Now, I've tried an array of just the strings with ObjectId's in them, similar to the eample, and I've also tried using ObjectId("STRINGHERE") ......
Read more >
Bookshelf.js | Home
It is designed to work with PostgreSQL, MySQL, and SQLite3. Website and documentation. The project is hosted on GitHub, and has a comprehensive...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found