Skip to content

[db:mongodb] Non-sparse unique index created for conditionally required fields #16298

@VeiaG

Description

@VeiaG

Describe the Bug

A field with unique: true and required: true always gets a non-sparse unique MongoDB index. Schema builder doesn't account for admin.condition which techincally makes this field conditionally required.

https://github.com/payloadcms/payload/blob/main/packages/db-mongodb/src/models/buildSchema.ts#L84

if (
  schema.unique &&
  (fieldShouldBeLocalized({ field, parentIsLocalized }) ||
    draftsEnabled ||
    (fieldAffectsData(field) &&
      field.type !== 'group' &&
      field.type !== 'tab' &&
      field.required !== true)) // ← only checks static required property
) {
  schema.sparse = true
}

The condition checks field.required !== true — the static property on the field definition. It does not account for admin.condition.

Proposed fix

In formatBaseSchema, treat a field as effectively optional for index purposes when required: true is combined with admin.condition:

// Before
field.required !== true

// After
field.required !== true || !!field.admin?.condition

This ensures that when a field is only conditionally required, a sparse unique index is created so that null values (from documents where the condition is false) are excluded from the uniqueness constraint.

I'm not sure about other db adapters.

Link to the code that reproduces this issue

https://github.com/payloadcms/payload/blob/main/packages/db-mongodb/src/models/buildSchema.ts#L84

Reproduction Steps

// Collection field definition
{
  name: 'slug',
  type: 'text',
  unique: true,
  required: true,
  admin: {
    condition: (data) => data.type === 'page', // only required for pages
  },
}
  1. Create a document where type !== 'page'slug is null.
  2. Create a second document where type !== 'page'slug is null again.
  3. MongoDB throws a unique constraint violation because the index is non-sparse and null is treated as a duplicate value.

Which area(s) are affected?

area: core, db: mongodb

Environment Info

Binaries:
  Node: 22.16.0
  npm: 10.9.2
  Yarn: N/A
  pnpm: 10.14.0
Relevant Packages:
  payload: 3.82.1
  next: 16.2.3
  @payloadcms/db-mongodb: 3.82.1
  @payloadcms/email-nodemailer: 3.82.1
  @payloadcms/graphql: 3.82.1
  @payloadcms/live-preview: 3.82.1
  @payloadcms/live-preview-react: 3.82.1
  @payloadcms/next/utilities: 3.82.1
  @payloadcms/plugin-nested-docs: 3.82.1
  @payloadcms/plugin-search: 3.82.1
  @payloadcms/plugin-seo: 3.82.1
  @payloadcms/richtext-lexical: 3.82.1
  @payloadcms/translations: 3.82.1
  @payloadcms/ui/shared: 3.82.1
  react: 19.2.3
  react-dom: 19.2.3
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.2.0: Tue Nov 18 21:09:40 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6000
  Available memory (MB): 16384
  Available CPU cores: 10

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions