-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Closed
Milestone
Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the bug has not already been reported
Mongoose version
9.0.
Node.js version
N/A
MongoDB server version
N/A
Typescript version (if applicable)
N/A
Description
When modifying multiple paths in a single save, the version mode (this.$__.version) can be incorrectly downgraded. This happens because the versioning logic uses direct assignment instead of accumulating with bitwise OR.
For example, if you:
- Push to a top-level array (should set VERSION_INC = 2)
- Set a value on an array index path (should set VERSION_WHERE = 1)
The second operation overwrites the first, resulting in VERSION_WHERE (1) instead of VERSION_ALL (3). This means __v is added to the query filter but NOT incremented, even though we pushed to an array.
Steps to Reproduce
const mongoose = require('mongoose');
const assert = require('assert');
run();
async function run() {
await mongoose.connect('mongodb://127.0.0.1:27017/test');
const Model = mongoose.model('Test', new mongoose.Schema({
items: [{ name: String }],
tags: [String]
}));
const doc = await Model.create({
items: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }],
tags: ['tag']
});
// Two clients load the same document
const clientA = await Model.findById(doc._id);
const clientB = await Model.findById(doc._id);
// Client A modifies the document
clientA.items.pull(clientA.items[0]._id); // pull (VERSION_INC)
clientA.tags[0] = 'modified'; // set index (VERSION_WHERE overwrites it)
await clientA.save();
// items is now ['item2', 'item3'], __v should be 1
const afterA = await Model.findById(doc._id);
assert.strictEqual(afterA.__v, 1, '__v should be incremented after pull');
// Client B has stale view, thinks items[1] is "item2"
clientB.items[1].name = 'item2-updated';
const err = await clientB.save().then(() => null, err => err);
assert.ok(err, 'save should throw VersionError due to stale __v');
assert.strictEqual(err.name, 'VersionError');
}Expected Behavior
When modifying multiple paths that trigger different version modes, the modes should be combined using bitwise OR:
- VERSION_WHERE (1) + VERSION_INC (2) = VERSION_ALL (3)
This ensures that:
__vis included in the query filter (for index safety)__vis incremented (to signal array position changes to other clients)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels