Skip to content

fix(setDefaultsOnInsert): run setters on default values during upsert#16093

Merged
vkarpov15 merged 1 commit intoAutomattic:9.4from
mahmoodhamdi:fix/issue-16051-setters-on-setDefaultsOnInsert
Mar 15, 2026
Merged

fix(setDefaultsOnInsert): run setters on default values during upsert#16093
vkarpov15 merged 1 commit intoAutomattic:9.4from
mahmoodhamdi:fix/issue-16051-setters-on-setDefaultsOnInsert

Conversation

@mahmoodhamdi
Copy link
Contributor

Problem

When using setDefaultsOnInsert with upsert operations, default values are not passed through setters. This means a schema like:

const schema = new Schema({
  name: String,
  slug: {
    type: String,
    default: 'Hello World!',
    set: function(v) {
      return v.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
    }
  }
});

will store slug as 'Hello World!' when upserted, instead of 'hello-world' (what you get with normal document creation).

Root Cause

In lib/helpers/setDefaultsOnInsert.js, schemaType.getDefault() was called with init = true. This causes _applySetters to skip all setters, since init is meant to signal that the value is being initialized and shouldn't go through setter transformations.

Solution

Changed init from true to false in the getDefault() call so setters run on default values, matching the behavior of normal document creation via new Model().

Also updated the existing test from gh-16025 which was asserting the old (buggy) behavior, and added a unit test in test/helpers/setDefaultsOnInsert.test.js.

How to Test

const schema = new Schema({
  name: String,
  slug: {
    type: String,
    default: 'Hello World!',
    set: v => v.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '')
  }
});
const Test = mongoose.model('Test', schema);

await Test.updateOne(
  { name: 'test' },
  { $set: { name: 'test' } },
  { upsert: true, setDefaultsOnInsert: true }
);

const doc = await Test.findOne({ name: 'test' });
assert.equal(doc.slug, 'hello-world'); // was 'Hello World!' before this fix

Fixes #16051

When using `setDefaultsOnInsert` with upsert, default values were not
being passed through setters. This happened because `getDefault()` was
called with `init = true`, which causes `_applySetters` to skip all
setters.

Changed `init` from `true` to `false` so setters run on defaults,
matching the behavior of normal document creation.

Fixes Automattic#16051
@vkarpov15 vkarpov15 added this to the 9.4 milestone Mar 15, 2026
Copy link
Collaborator

@vkarpov15 vkarpov15 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM although for caution I'll merge into 9.4. I don't expect this to be backwards breaking because setters already run on non-default values so I think it is reasonable to assume that setters already work on queries.

@vkarpov15 vkarpov15 changed the base branch from master to 9.4 March 15, 2026 21:19
@vkarpov15 vkarpov15 merged commit 8b37aae into Automattic:9.4 Mar 15, 2026
47 of 49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] setters do not run on setDefaultsOnInsert

2 participants