Automattic / Automattic/mongoose

(4.6.2 -> 4.6.3 regression) Calling .set on a subfield of a deselected subdoc wipes out other fields on the subdoc

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

Description

Suppose I have a schema defining a single embedded subdocument. I don't select this subdocument when I fetch the parent document, but I set a field on it anyway using .set.

In 4.6.2, this works as expected: the field I set changes, and the rest of the subdocument remains unchanged.

In 4.6.3, this wipes out the rest of the subdocument's fields, and gives it a new ID.

This feels like a bug, though it may be intended behavior.

``` javascript
const mongoose = require('mongoose');
const Promise = require('bluebird');

mongoose.Promise = Promise;
const connection = mongoose.connect('mongodb://localhost/minimal', {});
mongoose.set('debug', true);

const ballSchema = mongoose.Schema({
kind: String,
mass: Number
});

const sportSchema = mongoose.Schema({
ball: ballSchema
});

const Sport = mongoose.model('Sport', sportSchema);

new Sport({ball: {kind: 'birdie', mass: 4.75 }}).save()
.then((sport) => Sport.findById(sport._id).select('-ball'))
.then((sport) => {
sport.set('ball.kind', 'shuttlecock');

// On 4.6.2, this save issues this update:
// sports.update({ _id: ObjectId(...) },
// { '$set': { 'ball.kind': 'shuttlecock' } })
// On 4.6.3, it issues this update:
// sports.update({ _id: ObjectId("...") },
// { '$set': { ball: { kind: 'shuttlecock', _id: ObjectId("...") } } })
return sport.save();
})
.then((sport) => Sport.findById(sport._id).select('ball'))
.then((sport) => {
// On 4.6.2, sport.ball.mass === 4.7.5
// On 4.6.3, sport.ball.mass is undefined
console.log('sport.ball.mass', sport.ball.mass);
});
```

Contributor guide

Open the contributing guide

Research direction

Start by running the supplied JavaScript reproduction against Mongoose 4.6.3 and compare the generated update with the 4.6.2 behavior. Trace the .set('ball.kind', ...) and subsequent save() path for a deselected subdocument. Done means changing kind preserves mass and the existing subdocument ID instead of replacing the whole subdocument.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.