Mongoose: Regression: nested document not set when model initialised with new

Created on 22 Nov 2018  路  5Comments  路  Source: Automattic/mongoose

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

Sample code:

const mongoose = require('mongoose');
const {Schema} = mongoose;

const ActivityBareSchema = new Schema({
  _id: {
    type: Schema.Types.ObjectId,
    ref: 'Activity',
  },
  name: String,
});

const EventSchema = new Schema({
  activity: ActivityBareSchema,
  name: String,
});

const data = {
  _id: '5bf606f6471b6056b3f2bfc8',
  name: 'Test',
  activity: {
    _id: '5bf606f6471b6056b3f2bfc9',
    name: 'Activity name',
  },
};

const Event = mongoose.model('Event', EventSchema);
const event = new Event(data, null);

console.log(event);

What is the current behavior?
In 5.3.13, sample script outputs { _id: 5bf606f6471b6056b3f2bfc8, name: 'Test' } with the nested activity document missing.

What is the expected behavior?
In 5.3.4, the output included the activity subdocument:

{ _id: 5bf606f6471b6056b3f2bfc8, name: 'Test', activity: { _id: 5bf606f6471b6056b3f2bfc9, name: 'Activity name' } }

More details
We are passing null as the second parameter if we don't want to apply any data projection.
This is useful when we're using the aggregation framework to load documents, and then convert the results to models using new instantiation, like so:

const events = result.events.map(data => new Event(data, projection));

The projection that we pass in depends on what the user is querying, and if we want all fields the value for projection is null.

This was working fine up until 5.3.4, but after updating to 5.3.13 this no longer works. In effect, this is a breaking change?

Please mention your node.js, mongoose and MongoDB version.
Node 8.12.0, MongoDB 4.x.

confirmed-bug

All 5 comments

Docs about this were recently updated: https://github.com/Automattic/mongoose/commit/763ec8cee75406df172faa3cab798cd9235d87a0#diff-fc7fc7567205f95715daa4204b8ea0b0

Passing undefined instead of null fixes the issue, but imo null should still work the same. Trying to locate where it is failing in the code but no luck so far.

I suspect that this commit is the culprit somehow: https://github.com/Automattic/mongoose/commit/00e33ec1d16bc09976f87b723acd0092021bbd63

Thanks for reporting, will fix ASAP

Looks like this is an instance of my least favorite quirk from lodash.get:

$ node
> const get = require('lodash.get')
undefined
> get({ a: undefined }, 'a', {})
{}
> get({ a: null }, 'a', {})
null
> 

IMO this behavior is justifiable, but endlessly annoying. We'll add a wrapper internally so we don't get bitten by this going forward.

Oh that's what it was, I was trying to figure out Mongoose's own logic, didn't occur to me to check lodash. I don't like using that library all that much, so try to avoid it if I can!

Thanks for looking into it though, I will check it when the new version is released.

Was this page helpful?
0 / 5 - 0 ratings