Skip to content

fix(db-mongodb): serialize paginated count and docs inside transactions#17053

Open
brozmarek wants to merge 1 commit into
payloadcms:mainfrom
brozmarek:fix/db-mongodb/aggregate-paginate-transaction-session
Open

fix(db-mongodb): serialize paginated count and docs inside transactions#17053
brozmarek wants to merge 1 commit into
payloadcms:mainfrom
brozmarek:fix/db-mongodb/aggregate-paginate-transaction-session

Conversation

@brozmarek

Copy link
Copy Markdown

What

Serializes paginated count and document queries when a MongoDB transaction session is active.

  • packages/db-mongodb/src/utilities/aggregatePaginate.ts: when a session is present, await the aggregate docs query before awaiting the count query. The existing Promise.all path is preserved when no session is active, so non-transactional reads keep their parallel performance
  • packages/db-mongodb/package.json: bump mongoose-paginate-v2 from 1.9.4 to 1.9.5, which brings in the equivalent session-aware fix for the regular Model.paginate path (aravindnc/mongoose-paginate-v2#242). I contributed to that upstream PR, so this Payload change applies the same transaction-session fix to the adapter-owned aggregate pagination path

This covers both pagination entry points in the adapter: the custom aggregatePaginate utility, used by find.ts and queryDrafts.ts when joins or sort aggregation are involved, and the standard Model.paginate path used by find.ts, queryDrafts.ts, findVersions.ts, and findGlobalVersions.ts.

Why

MongoDB allows only one in-flight operation per transaction session at a time. Payload's pagination previously issued the count query and the docs query concurrently on the same session, which violates that rule and can produce errors such as:

Given transaction number X does not match any in-progress transactions

This can affect paginated collection, draft, and version queries executed inside a Payload transaction. The serialization is gated on session, so the only cost is one extra round trip per count for transactional reads. Non-transactional paginated reads are unchanged.

Validation

Added a Mongo-only regression test in test/database/int.spec.ts (should run paginated find operations inside a transaction session) that runs both pagination paths inside a single transaction session:

  • A regular paginated payload.find on the simple collection, which exercises
    Model.paginate.
  • A paginated payload.find on posts sorted by category.title, which forces the
    aggregatePaginate branch via buildSortParam's relationship sort aggregation.

Both queries now succeed within the same session and return the expected totalDocs.

Run against a local MongoDB replica set because transactions require a replica set. With the default test Docker service:

PAYLOAD_DATABASE=mongodb pnpm exec vitest run test/database/int.spec.ts --project int -t "should run paginated find operations inside a transaction session"

For my local no-auth MongoDB replica set, I used:

$env:PAYLOAD_DATABASE='mongodb'
$env:MONGODB_URL='mongodb://127.0.0.1:27018/payload?directConnection=true&replicaSet=rs0'
pnpm exec vitest run test/database/int.spec.ts --project int --no-cache -t "should run paginated find operations inside a transaction session"

Without the fix, the test fails with the transaction-number error above. With the fix, it passes.

Also verified:

  • Prettier passes for the changed files
  • ESLint exits successfully for the changed files
  • Type declaration builds pass:
    • pnpm --filter @payloadcms/translations build:types
    • pnpm --filter payload build:types
    • pnpm --filter @payloadcms/db-mongodb build:types

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedmongoose-paginate-v2@​1.9.510010010088100

View full report

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.

1 participant