Skip to content

Commit c393154

Browse files
authored
Merge pull request Automattic#15114 from Automattic/vkarpov15/Automatticgh-15108
fix(map): clean modified subpaths when overwriting values in map of subdocs
2 parents 0fd43c4 + 66a8b87 commit c393154

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

lib/types/map.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const handleSpreadDoc = require('../helpers/document/handleSpreadDoc');
99
const util = require('util');
1010
const specialProperties = require('../helpers/specialProperties');
1111
const isBsonType = require('../helpers/isBsonType');
12+
const cleanModifiedSubpaths = require('../helpers/document/cleanModifiedSubpaths');
1213

1314
const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
1415

@@ -157,7 +158,13 @@ class MongooseMap extends Map {
157158
super.set(key, value);
158159

159160
if (parent != null && parent.$__ != null && !deepEqual(value, priorVal)) {
160-
parent.markModified(fullPath.call(this));
161+
const path = fullPath.call(this);
162+
parent.markModified(path);
163+
// If overwriting the full document array or subdoc, make sure to clean up any paths that were modified
164+
// before re: #15108
165+
if (this.$__schemaType.$isMongooseDocumentArray || this.$__schemaType.$isSingleNested) {
166+
cleanModifiedSubpaths(parent, path);
167+
}
161168
}
162169

163170
// Delay calculating full path unless absolutely necessary, because string

test/types.map.test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,4 +1103,51 @@ describe('Map', function() {
11031103
assert.equal(doc.addresses.get('home').length, 1);
11041104
assert.equal(doc.addresses.get('home')[0].city, 'London');
11051105
});
1106+
1107+
it('clears nested changes in subdocs (gh-15108)', async function() {
1108+
const CarSchema = new mongoose.Schema({
1109+
owners: {
1110+
type: Map,
1111+
of: {
1112+
name: String
1113+
}
1114+
}
1115+
});
1116+
const CarModel = db.model('Car', CarSchema);
1117+
const car = await CarModel.create({
1118+
owners: { abc: { name: 'John' } }
1119+
});
1120+
1121+
car.owners.get('abc').name = undefined;
1122+
car.owners.delete('abc');
1123+
assert.deepStrictEqual(car.getChanges(), { $unset: { 'owners.abc': 1 } });
1124+
await car.save();
1125+
1126+
const doc = await CarModel.findById(car._id);
1127+
assert.strictEqual(doc.owners.get('abc'), undefined);
1128+
});
1129+
1130+
it('clears nested changes in doc arrays (gh-15108)', async function() {
1131+
const CarSchema = new mongoose.Schema({
1132+
owners: {
1133+
type: Map,
1134+
of: [{
1135+
_id: false,
1136+
name: String
1137+
}]
1138+
}
1139+
});
1140+
const CarModel = db.model('Car', CarSchema);
1141+
const car = await CarModel.create({
1142+
owners: { abc: [{ name: 'John' }] }
1143+
});
1144+
1145+
car.owners.get('abc')[0].name = undefined;
1146+
car.owners.set('abc', [{ name: 'Bill' }]);
1147+
assert.deepStrictEqual(car.getChanges(), { $inc: { __v: 1 }, $set: { 'owners.abc': [{ name: 'Bill' }] } });
1148+
await car.save();
1149+
1150+
const doc = await CarModel.findById(car._id);
1151+
assert.deepStrictEqual(doc.owners.get('abc').toObject(), [{ name: 'Bill' }]);
1152+
});
11061153
});

0 commit comments

Comments
 (0)