Skip to content
Merged
14 changes: 10 additions & 4 deletions lib/helpers/model/castBulkWrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ module.exports = function castBulkWrite(originalModel, op, options) {
if (model.schema.$timestamps != null && op['updateOne'].timestamps !== false) {
const createdAt = model.schema.$timestamps.createdAt;
const updatedAt = model.schema.$timestamps.updatedAt;
applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateOne']['update'], {});
applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateOne']['update'], {
timestamps: op['updateOne'].timestamps
});
}

if (op['updateOne'].timestamps !== false) {
Expand Down Expand Up @@ -100,7 +102,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
op['updateOne']['update'] = castUpdate(model.schema, op['updateOne']['update'], {
strict: strict,
overwrite: false,
upsert: op['updateOne'].upsert
upsert: op['updateOne'].upsert,
overwriteImmutable: op['updateOne'].overwriteImmutable
}, model, op['updateOne']['filter']);
} catch (error) {
return callback(error, null);
Expand Down Expand Up @@ -136,7 +139,9 @@ module.exports = function castBulkWrite(originalModel, op, options) {
if (model.schema.$timestamps != null && op['updateMany'].timestamps !== false) {
const createdAt = model.schema.$timestamps.createdAt;
const updatedAt = model.schema.$timestamps.updatedAt;
applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {});
applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {
timestamps: op['updateMany'].timestamps
});
}
if (op['updateMany'].timestamps !== false) {
applyTimestampsToChildren(now, op['updateMany']['update'], model.schema);
Expand All @@ -158,7 +163,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
strict: strict,
overwrite: false,
upsert: op['updateMany'].upsert
upsert: op['updateMany'].upsert,
overwriteImmutable: op['updateMany'].overwriteImmutable
}, model, op['updateMany']['filter']);
} catch (error) {
return callback(error, null);
Expand Down
4 changes: 2 additions & 2 deletions lib/helpers/query/castUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, pref) {

if (op !== '$setOnInsert' &&
!options.overwrite &&
handleImmutable(schematype, strict, obj, key, prefix + key, context)) {
handleImmutable(schematype, strict, obj, key, prefix + key, options, context)) {
continue;
}

Expand Down Expand Up @@ -335,7 +335,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, pref) {
// You can use `$setOnInsert` with immutable keys
if (op !== '$setOnInsert' &&
!options.overwrite &&
handleImmutable(schematype, strict, obj, key, prefix + key, context)) {
handleImmutable(schematype, strict, obj, key, prefix + key, options, context)) {
continue;
}

Expand Down
6 changes: 5 additions & 1 deletion lib/helpers/query/handleImmutable.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const StrictModeError = require('../../error/strict');

module.exports = function handleImmutable(schematype, strict, obj, key, fullPath, ctx) {
module.exports = function handleImmutable(schematype, strict, obj, key, fullPath, options, ctx) {
if (schematype == null || !schematype.options || !schematype.options.immutable) {
return false;
}
Expand All @@ -15,6 +15,10 @@ module.exports = function handleImmutable(schematype, strict, obj, key, fullPath
return false;
}

if (options && options.overwriteImmutable) {
return false;
}

if (strict === false) {
return false;
}
Expand Down
30 changes: 30 additions & 0 deletions test/model.updateOne.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2707,6 +2707,36 @@ describe('model: updateOne: ', function() {
assert.equal(doc.age, 20);
});

it('overwriting immutable createdAt with bulkWrite (gh-15781)', async function() {
const start = new Date().valueOf();
const schema = Schema({
createdAt: {
type: mongoose.Schema.Types.Date,
immutable: true
},
name: String
}, { timestamps: true });

const Model = db.model('Test', schema);

await Model.create({ name: 'gh-15781' });
let doc = await Model.collection.findOne({ name: 'gh-15781' });
assert.ok(doc.createdAt.valueOf() >= start);

const createdAt = new Date('2011-06-01');
assert.ok(createdAt.valueOf() < start.valueOf());
await Model.bulkWrite([{
updateOne: {
filter: { _id: doc._id },
update: { name: 'gh-15781 update', createdAt },
overwriteImmutable: true,
timestamps: false
}
}]);
doc = await Model.collection.findOne({ name: 'gh-15781 update' });
assert.equal(doc.createdAt.valueOf(), createdAt.valueOf());
});

it('updates buffers with `runValidators` successfully (gh-8580)', async function() {
const Test = db.model('Test', Schema({
data: { type: Buffer, required: true }
Expand Down
Loading