Skip to content

Conversation

baileympearson
Copy link
Contributor

@baileympearson baileympearson commented Oct 13, 2025

Description

Summary of Changes

Cursors no longer provide a default batchSize of 1000 for getMores.

Notes for Reviewers

What is the motivation for this change?

Release Highlight

Cursors no longer provide a default batchSize of 1000 for getMores

In driver versions <7.0, the driver provides a default batchSize of 1000 for each getMore when iterating a cursor. This behavior is not ideal because the default is set regardless of the documents being fetched. For example, if a cursor fetches many small documents, the driver's default of 1000 can result in many round-trips to fetch all documents, when the server could fit all documents inside a single getMore if no batchSize were set.

Now, cursors no longer provide a default batchSize when executing a getMore. A batchSize will only bet set on getMore commands if a batchSize has been explicitly configured for the cursor.

Double check the following

  • Lint is passing (npm run check:lint)
  • Self-review completed using the steps outlined here
  • PR title follows the correct format: type(NODE-xxxx)[!]: description
    • Example: feat(NODE-1234)!: rewriting everything in coffeescript
  • Changes are covered by tests
  • New TODOs have a related JIRA ticket

Comment on lines +522 to 525
// Generate docs
const docs = [];
for (let i = 0; i < 3500; i++) docs.push({ a: i });

Copy link
Contributor Author

@baileympearson baileympearson Oct 14, 2025

Choose a reason for hiding this comment

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

Before the changes in this PR, this test relied on a combination of server behavior and driver defaults to pass. getMore always set a batchSize of 1000, and local testing showed the server returning 101 documents for the aggregate. So, 100 documents for the aggregate + 1000 for each getMore results in 3 getMores to exhaust the cursor.

This test fails now that we don't have a default batchSize on getMores because cursor exhaustion is reached in fewer than 3 getMores. To make the test reliable and reproducible, I added a batchSize: 1000 argument to the aggregate. However, this also sets the batchSize for the initial aggregate, so we need a few more documents (1000ish more) in order for the test to pass.

Comment on lines +123 to +143
// TODO(DRIVERS-1448): Remove logic to enforce `limit` in the driver
let cleanup: () => void = noop;
const { batchSize } = this.cursorOptions;
if (batchSize != null && batchSize > remaining) {
this.cursorOptions.batchSize = remaining;

// After executing the final getMore, re-assign the batchSize back to its original value so that
// if the cursor is rewound and executed, the batchSize is still correct.
cleanup = () => {
this.cursorOptions.batchSize = batchSize;
};
}

const response = await super.getMore(batchSize);
// TODO: wrap this in some logic to prevent it from happening if we don't need this support
this.numReturned = this.numReturned + response.batchSize;
try {
const response = await super.getMore();

return response;
this.numReturned = this.numReturned + response.batchSize;

return response;
} finally {
cleanup?.();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like cleanup functions, and they naturally work well with explicit resource management (for whenever we can use resource management in the driver):

using stack = new DisposableStack();
stack.defer(() => ( this.cursorOptions.batchSize = batchSize ) );

But I'm happy to rework this if people prefer an alternative approach (i.e., manually assigning the value in a try-finally). Just lmk what the preference is.

@baileympearson baileympearson marked this pull request as ready for review October 14, 2025 15:38
@baileympearson baileympearson requested a review from a team as a code owner October 14, 2025 15:38
@durran durran self-assigned this Oct 15, 2025
@durran durran added the Primary Review In Review with primary reviewer, not yet ready for team's eyes label Oct 15, 2025
// TODO(DRIVERS-1448): Remove logic to enforce `limit` in the driver
let cleanup: () => void = noop;
const { batchSize } = this.cursorOptions;
if (batchSize != null && batchSize > remaining) {
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious about the reasoning for this. What is the harm of sending a batch size greater than the number of remaining documents? Can this block just be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did you read the DRIVERS ticket?

Its here historically because the legacy wire protocol required it (it required drivers to enforce the limit). Then unified tests were added that enforce this behavior. It's not needed anymore but the unified tests still exist.

@baileympearson baileympearson requested a review from durran October 15, 2025 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Primary Review In Review with primary reviewer, not yet ready for team's eyes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants